根据gps coords更新谷歌地图位置

时间:2011-12-28 23:22:52

标签: javascript python html5 google-maps

我有一个带有GPS芯片的Arduino,处理带有python的NMEA字符串。我有一个HTML文件,我打开并每隔x秒自动刷新一次。标记更新,但我真的希望能够更新位置信息而无需刷新。我知道它可以通过拖放来完成这里演示:http://gmaps-samples-v3.googlecode.com/svn/trunk/draggable-markers/draggable-markers.html但我需要知道如何替换拖拽事件而不是接口w / python推出新坐标。我需要一种将新坐标信息添加到网页中的方法。任何帮助/建议将不胜感激。唯一真正适用于此问题的类是GoogleMap。我不熟悉很多网页内容,所以越简单越好。

我有什么:

python - >打开网页w / autoreload python - >在map.html上插入新的坐标 map.html刷新并拾取并显示新位置

我想要的是什么:

python - >新位置{{}}标记移至新坐标

import  re
import  sys
import  copy
import  time
import  threading
import  Queue
import  serial
import  webbrowser
import  traceback
import  random
import  math
import  turtle
from    pprint         import pprint
from    collections    import OrderedDict

class MockIo(object):

    def __init__(self):
        pass

    def read(self,buff):
        lat = str(random.random())[2:6]
        lon = str(random.random())[2:6]
        return "$GPGGA,172307.000,3913.%s,N,07716.%s,W,2,10,0.8,199.9,M,-33.4,M,3.8,0000*46\r\n" % (lat,lon)

    def write(self,buff):
        pass

class GPSTurtle(object):

    def __init__(self, new_x = 0, new_y = 0):
        self.t = turtle.Turtle()
        self.x_coord = new_x
        self.y_coord = new_y

        self.diff_x  = 0
        self.diff_y  = 0
        self.heading = 0
        self.origin_x = 0
        self.origin_y = 0

    def initialize_origin(self, new_x, new_y):
        self.origin_x = self.origin_x - new_x
        self.origin_y = self.origin_y - new_y

    def __update_pos(self, new_x, new_y):
        new_x       += self.origin_x
        new_y       += self.origin_y
        new_x *= 20
        new_y *= 20
        self.diff_x  = new_x - self.x_coord
        self.diff_y  = new_y - self.y_coord
        if 0 == self.diff_x:
            if self.diff_y > 0:
                self.heading = 90
            elif self.diff_y < 0:
                self.heading = 270
        elif 0 == self.diff_y:
            if self.diff_x > 0:
                self.heading = 0
            elif self.diff_x < 0:
                self.heading = 180
        else:
            self.heading = math.degrees(math.atan(float(self.diff_y)/float(self.diff_x)))
            if self.diff_x < 0:
                self.heading += 180
            elif self.diff_y < 0:
                self.heading += 360

        self.set_pos(new_x, new_y)
        print self.diff_x,self.diff_y,self.heading,self.x_coord,self.y_coord

    def set_pos(self, new_x, new_y):
        self.x_coord = new_x
        self.y_coord = new_y

    def __draw(self):
        self.t.setheading(self.heading)
        self.t.pendown()
        self.t.goto(self.x_coord, self.y_coord)
        self.t.penup()

    def ungps(self, new_x, new_y):
        new_x = int(1000.0 * new_x)
        new_y = int(1000.0 * new_y)
        return (new_x, new_y)

    def update_and_draw(self, new_x, new_y):
        self.__update_pos(new_x, new_y)
        self.__draw()




class GPS(threading.Thread):

    def __init__(self, comport = 'COM15', baud = 4800):
        super(GPS, self).__init__()
        self.GOOD       = True
        self.gpgga_keys =   [
                                'message_id',
                                'utc_time',
                                'lattitude',
                                'n_s_ind',
                                'longitude',
                                'e_w_ind',
                                'pos_fix_ind',
                                'satellites',
                                'hdop',
                                'msl_altitude',
                                'units_1',
                                'geoid_sep',
                                'units_2',
                                # 'age_of_diff_corr', gps does not have this field by default
                                'diff_ref_station_id',
                                'checksum',
                            ]
        self.PSRF103    =   {
                                'name':'$PSRF103',
                                'msg':{'GGA':'00','GLL':'01','GSA':'02','GSV':'03','RMC':'04','VTG':'05'},
                                'mode':{'SetRate':'00','Query':'01'},
                                'rate':{'off':'00','min':'01','max':'255'},
                                'cksumEnable':{'disable':'00','enable':'01'},
                            }
        self.gps_msg_q  = Queue.Queue()
        self.gps_buff   = ""
        try:
            self.gps_com    = serial.Serial(   
                                                comport, 
                                                baud, 
                                                timeout = 1,
                                                parity  = serial.PARITY_NONE,
                                                rtscts  = 0,
                                                xonxoff = 0
                                            )
        except serial.serialutil.SerialException:
            print "Could not open com port, assuming simulation mode and setting"
            print "com object to MockIo"
            self.gps_com = MockIo()

    def enable_all(self):
        m  = self.PSRF103
        for msg in m['msg'].values():
            st = ','.join([m['name'],msg,m['mode']['Query'],m['rate']['on'],m['cksumEnable']['enable']])
            st = self.append_crc(st)
            self.send_msg(st)
        self.gps_com.read(4028)

    def disable_all(self):
        m  = self.PSRF103
        for msg in m['msg'].values():
            st = ','.join([m['name'],msg,m['mode']['Query'],m['rate']['off'],m['cksumEnable']['enable']])
            st = self.append_crc(st)
            self.send_msg(st)
        self.gps_com.read(4028)

    def append_crc(self,st):
        match     = re.compile("\$(.*)")
        crc        = 0

        if match.search(st):
            st = match.search(st).group(1)

        for letter in st:
            crc = crc ^ ord(letter)
        return "$%s*%0.2x\r\n" % (st,crc)

    def run(self):
        self.disable_all()
        while self.GOOD:
            self.send_GPGGA_req()
            time.sleep(2)

    def send_GPGGA_req(self):
        m  = self.PSRF103
        st = ','.join([m['name'],m['msg']['GGA'],m['mode']['Query'],m['rate']['off'],m['cksumEnable']['enable']])
        st = self.append_crc(st)
        self.send_msg(st)

    def parse_msg(self,st):
        '''
            SAMPLE GPGGA MSG
            "$GPGGA,172307.000,3913.7428,N,07716.7474,W,2,10,0.8,199.9,M,-33.4,M,3.8,0000*46\r\n"
        '''
        retVal = (False,None)
        st     = st.rstrip('\r\n')
        parse  = st.split(',')
        if st.startswith('$GPGGA') and len(self.gpgga_keys) == len(parse):
            retVal = (True, OrderedDict(zip(self.gpgga_keys,parse)))
        else:
            pass

        return retVal

    def send_msg(self, st):
        self.gps_com.write(st)
        self.gps_buff = ''.join([self.gps_buff,self.gps_com.read(1024)])
        buffsplit     = re.compile(r'.*?\r\n|.+')
        splt          = buffsplit.findall(self.gps_buff)
        if 0 < len(splt):
            if splt[-1].endswith('\r\n'):
                self.add_list_to_q(splt)
                self.gps_buff = ""
            else:
                self.add_list_to_q(splt[:-1])
                self.gps_buff = splt[-1]

    def add_list_to_q(self,list_):
        for item in list_:
            self.gps_msg_q.put(item,False)

    def get_item_from_q(self, block = True, timeout = 10):
        return self.gps_msg_q.get(block, timeout)

    def convert_lat_lon(self, lat, lon,ns,ew):
        lat = "%f" % (float(lat[:-7]) + (float(lat[-7:])/60.0))
        lon = "%f" % (float(lon[:-7]) + (float(lon[-7:])/60.0))
        if 'S' == ns:
            lat = str(float(lat) * -1.0)
        if 'W' == ew:
            lon = str(float(lon) * -1.0)
        return (lat,lon)




class GoogleMap(object):

    def __init__(self, path = 'map.html'):
        self.path = path
        self.map_html = '''
                            <!DOCTYPE html>
                            <html>
                            <head>
                            <meta http-equiv="refresh" content="5" /> 
                            <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
                            <style type="text/css">
                              html { height: 100% }   body { height: 100%; margin: 0px; padding: 0px }   #map_canvas { height: 100% } </style>
                            <script type="text/javascript"
                                   src="http://maps.google.com/maps/api/js?sensor=true">
                            </script>
                            <script type="text/javascript">
                               function initialize() {
                                   var lat = %s
                                   var lng = %s
                                   var latlng = new google.maps.LatLng(lat,lng);
                                   var myOptions = {
                                       zoom: 13,
                                       center: latlng,
                                       mapTypeId: google.maps.MapTypeId.ROADMAP
                                   };
                                   var map    = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
                                   var marker = new google.maps.Marker({position: latlng, map: map, title: %s });
                               }
                            </script>
                            </head>
                            <body onload="initialize()">
                              <div id="map_canvas" style="width:100%; height:100%"></div>
                            </body>
                            </html>
                        '''

    def write_map(self,lat = '39.229013',long = '-77.445735',marker = '""'):
        new_map_html = self.map_html % ( str(lat), str(long), str(marker).replace('"','') )
        with open(self.path, 'w') as f:
            f.write(new_map_html)

    def launch_browser(self):
        webbrowser.open_new_tab(self.path)



if __name__ == "__main__":
    map = GoogleMap('map.html')
    map.write_map()
    map.launch_browser()

    gps = GPS('COM15',4800)
    gps.start()

    t = GPSTurtle()
    first_update = True

    try:
        while True:
            try:
                st = gps.get_item_from_q(True,2)
                success,gpgga = gps.parse_msg(st)
                if success:
                    lat, lon = gps.convert_lat_lon( gpgga['lattitude'],
                                                    gpgga['longitude'],
                                                    gpgga['n_s_ind'],
                                                    gpgga['e_w_ind'])
                    la,ln = t.ungps(float(lat),float(lon))
                    if first_update:
                        t.initialize_origin(la,ln)
                        first_update = False
                    else:
                        t.update_and_draw(la,ln)

                    map.write_map(lat,lon,'ME!')
                    time.sleep(5)
            except Queue.Empty:
                # pass
                print "Q-Empty"
    except:
        gps.GOOD = False
        gps.join()
        print "\n\nEXITING PROGRAM\n\n"
        traceback.print_exc(file=sys.stdout)

1 个答案:

答案 0 :(得分:1)

您可以设置ajax短轮询,而不是刷新,实际上是使用终点检查页面,该终点每隔几秒返回一次标记的位置。这是一篇文章,谈论它并链接到教程:Real-time data on webpage with jQuery

另一种方法是设置长轮询 - 让页面与服务器保持打开连接,等待更新。最大的好处是,一旦坐标发生变化,您的UI就会得到更新。最大的缺点是,这会给您的服务器带来相当大的负担,要求它保持开放的连接。缩放长轮询更难。

这篇文章总结了两个选项:Short-polling vs Long-polling for real time web applications?

修改

这是一个相当粗略的例子,但它应该为您提供一个简单的框架来持续更新lat。事先道歉,因为我的经验是有限的,没有使用网络服务器,我使用最简单的设置,我能想到 - 谷歌应用程序引擎SDK。它配备了一个易于安装和运行的开发服务器。以下是SDK的链接:http://code.google.com/appengine/downloads.html

main.py:

#!/usr/bin/env python

import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

def doRender(handler, page, templatevalues=None):
    path = os.path.join(os.path.dirname(__file__), page)
    handler.response.out.write(template.render(path, templatevalues))

class MainHandler(webapp.RequestHandler):
    def get(self):
        doRender(self, 'template/main.html')


class AjaxHandler(webapp.RequestHandler):
    def get(self):
        self.response.out.write('{ "lat": "1", "long": "1"}')

def main():
    application = webapp.WSGIApplication([('/', MainHandler),
                                          ('/data.js', AjaxHandler)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()

的app.yaml:

application: ajaxtest
version: 1
runtime: python
api_version: 1

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: .*
  script: main.py

main.html(将此文件放在项目根文件夹下的“模板”文件夹中):

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>

</head>
<body>
<button>Get JSON data</button>
<div></div>
<script type="text/javascript">
var test = 1;

function update(){
    $.getJSON("/data.js",function(data){

    var items = [];
      $.each(data, function(key, val){
        $("div").append(key + ":" + val + " ");
      });
    });
    }

var t=setInterval("update()",1000);

</script>
</body>
</html>

出于您的目的,修改AjaxHandler以重新查询GPS坐标。同时修改$(“div”)。append(key +“:”+ val +“”);向谷歌地图发送更新以获取标记的坐标。

如果这没有帮助,或者如果你没有扭曲的运气,请告诉我。我今天下班了,所以应该能够投入更多的时间。祝你好运!