GPS tracking using SVG - Part 2

a paper for the 2002 and 2003 SVG Open Developers Conference.

Continued from part 1

Where we left off:

We solved some interesting issues with regard to coordinate projection, and built an example, that loads in coordinates from an xml file, and plots a vehicle's movement over a map:

The SVG file:
example2.svg (Opens in a new window)

The color-coded source-code:
example2.html

So that's great, our application does exactly what we want it to.
There's just one thing though - the map isn't too great.
If this is to be of any use we'll need higher resolution maps, but without needing a massive download or it will slow the thing down too much.

Take it to the next level:

That's literally what we'll do - add new levels of detail, and tie them in with SVG's zoomlevels.
The way this works, is that we load higher resolution maps, covering a smaller area, as we zoom in, like this:

Fig.1 to 5 - Increasing detail as we zoom-in:

Level 0 (not zoomed)
Increasing zoom levels

Level 1
Increasing zoom levels

Level 2
Increasing zoom levels

Level 3
Increasing zoom levels

Level 4
Increasing zoom levels

There are two ways of loading the higher resolution maps,

  1. Load the map-segments into a grid, usually using bounding-box measurements in feet. As we move close to the grid-border, the next segment is loaded. The sections are cached on the server, or locally on HD/CD.
  2. Load the maps centred on our vehicle-icon. As we move towards the edge of the map-segment, a new map is loaded, again centred on our vehicle-icon. The maps are created dynamically on the server, depending on the Longitude/Latitude we use in the map's URL-string.

In this case I am going to use the second method - although both have their merits, depending on the situation.
Let's put together a to-do list again:

  1. We need a map-server that returns centered maps on Longitude/Latitude requests.
  2. Catch our SVG's onzoom event, and determine what zoomlevel we're at.
  3. Add an <image> to our SVG, to load the map into.
  4. Make a loadMap() function that loads the map into the image, and positions it correctly.
  5. Call this function when the user zooms in or out, to show the correct map resolution.
  6. Add some of the final touches, like panning the window.
Ok, let's see about Step 1:

Naturally setting up a map-server is no small feat, and will require the necessary licenses to be paid and servers to be set-up.
So for the scope of this paper, and purely for educational purposes I'll use an existing, publicly available map server.
We even have a choice:

There are probably many others too, but I'll use mappoint for this exercise.
To start off we need to know what parameters we can pass in the map-server's URL, here's a URL breakdown:

URL:http://msrvmaps.mappoint.net/isapi/MSMap.dll
ID:(probably used for internal access-control)?ID=3XNsF.
Lat/Lon:&C=44.96,-93.22
Country code - could also be EUR0809 for instance.&L=USA0409
Unknown - needs to be set to "1"&CV=1
Zoom level - 1 is very close, 22000 is the whole world (cool!)&A=285
Image size(in pixels)&S=1000,1000
Offset (Used for panning, not needed in this case)&O=-0,0

Try it, Minneapolis up close:

http://msrvmaps.mappoint.net/isapi/MSMap.dll?ID=3XNsF.&C=44.96,-93.22&L=USA0409&CV=1&A=1&S=500,500&O=-0,0

or viewed from outer-space:

http://msrvmaps.mappoint.net/isapi/MSMap.dll?ID=3XNsF.&C=44.96,-93.22&L=USA0409&CV=1&A=22000&S=500,500&O=-0,0

(Open in new windows)

Disclaimer: Like I said, we use this service for personal,educational, non-commercial use only.
If you are interested in commercial use contact the companies involved.

Update:

Mappoint have changed their service, and attempts to update these URLs result in a message requesting not to link to their servers directly.
So I changed the examples to use the US census maps. These are not very good quality, but are free.
To update the code, replace this line:

 mapLoader.setAttribute("xlink:href","http://msrvmaps.mappoint.net/isapi/MSMap.dll?ID=3XNsF.&C="+parseFloat(LATITUDE)+","+parseFloat(LONGITUDE)+"&L=USA0409&CV=1&A="+zoom+"&S="+res+","+res+"&O=-0,0");

With these:

 var myzoom=zoom*0.0056;
 mapLoader.setAttribute("xlink:href","http://tiger.census.gov/cgi-bin/mapper/map.png?lat="+parseFloat(LATITUDE)+"&lon="+parseFloat(LONGITUDE)+"&wid="+myzoom+"&ht="+myzoom+"&iht="+res+"&iwd="+res+"&conf=palette1.con&on=cities&on=counties&on=majroads&on=places&on=shorelin&on=interstate&on=statehwy&on=states&on=ushwy&on=water");

OK, now for Step 2:

Catching the onzoom event, and recognising what zoomlevel we're at isn't that hard:

<svg onzoom="catchZoom()">
<rect x="80px" y="10px" width="40px" height="40px" /> 
<script>
	function catchZoom(){
		if (!window.svgDocument)svgDocument = evt.target.ownerDocument;
		alert("currentScale = "+svgDocument.rootElement.currentScale)
	}
</script>
</svg> 

Open the example, and zoom in or out - an alert will show the currentScale. This ranges from 0.0625 to 16, 1 being original size.

Example 3:

example3.svg (Opens in a new window)

At this point we have to drop Batik support, as Batik doesn't have the onzoom event implemented yet.
It has however been mentioned as a feature request, so it's likely to be added soon.

In Step 3 we add an image to our SVG:

We'll use this image to load our dynamic maps.
I also add a line in init() to get a handle on the image, so we can alter it's "xlink:href" property later.
To keep things simple I'll just use one image for now. Normally we'd use two, to avoid flashing while a map is loading.
for the moment we load a placekeeper image - pk.jpg.
width="200px" height="200px" are temporary values.

<svg οnlοad="init()">
	<image id="detail" width="200px" height="200px" xlink:href="images/pk.jpg" />
	<script type="text/ecmascript">
		function init(){
			if (!window.svgDocument)svgDocument = evt.target.ownerDocument;
			mapLoader=svgDocument.getElementById("detail")	
		}
	</script>
</svg> 
In Step 4 we add a "loadMap()" function:

This loads the map into the image, and positions it correctly.

function loadMap(lonDist,latDist,LONGITUDE,LATITUDE){
	vehicle.lastxfeet=lonDist
	vehicle.lastyfeet=latDist
	//We set some default values. These should always have the same proportion to each other,
	//so we can divide all three, or multiply all three by the same amount.
	//Multiplying times 2 loads large map (large area), dividing by two loads small maps (modem users)
	var startSize=120000
	var startZoom=60
	var startRes=350 
	
	//We use the currentScale to get a usable multiplication coefficient.
	c=(svgDocument.rootElement.currentScale/2)+0.8
	
	var res=Math.round(startRes+((startRes/8)*c))
	var zoom=Math.round(startZoom/c)
	//As we have to pass integers in the URL, we check what the rest was, to adjust the display size accordingly:
	var zoomRest=(zoom/(startZoom/c))
	//Load the map passing the coords and size
	var myzoom=zoom*0.0056;
 	mapLoader.setAttribute("xlink:href","http://tiger.census.gov/cgi-bin/mapper/map.png?lat="+parseFloat(LATITUDE)+"&lon="+parseFloat(LONGITUDE)+"&wid="+myzoom+"&ht="+myzoom+"&iht="+res+"&iwd="+res+"&conf=palette1.con&on=cities&on=counties&on=majroads&on=places&on=shorelin&on=interstate&on=statehwy&on=states&on=ushwy&on=water");
	
	//Calculate what size to display the map at + set size:
	var width=((startSize/c)*zoomRest)+res*2
	var height=((startSize/c)*zoomRest)+res*2
	mapLoader.setAttribute("width",width)
	mapLoader.setAttribute("height",height)
	vehicle.mapLoaderSize=width
	//Calculate what location to display the map at + move:
	var xVal=parseInt(lonDist)-(width/2)
	var yVal=parseInt(latDist)-(height/2)
	var cont="translate("+xVal+" "+yVal+")"
	mapLoader.setAttribute("transform", cont)
	//Set the viewers size:
	vehicle.setSize(c)
}
In Step 5 we call "loadMap()" when the user zooms in or out:

This allows us to show the correct map resolution depending on how close we're zoomed in.
The onzoom event calls "catchZoom()". This basically tests the zoom-level, and loads a new image appropriate to that zoom-level.

In Step 6 we add a few finishing touches:

We keep track of the distance covered from the initial loading coordinate, so we can load the next map segment when our vehicle approaches the map's edge.
We use feet, instead of Lon/Lat for this, as the feet scale 1:1 to pixels in the SVG. So if we know our map's image is 500px wide, then if our vehicle travels more than 200 feet from the initial position, we load the next map (by setting border=true)- again centred on the vehicles position, and reset the lastxVal and lastyVal variables.

Another thing to fix is that we want our browser's viewport to follow the vehicle, so the vehicle remains visible as it moves.
The way I did this works well, despite it's simplicity:

	var difx=(this.xfeet[i-1]-this.xfeet[i])
	var dify=(this.yfeet[i-1]-this.yfeet[i])
	var cof=(200000/Math.min(window.innerHeight,window.innerWidth))/d.currentScale
	d.currentTranslate.y+=(dify/cof)
	d.currentTranslate.x+=(difx/cof)
	

In line 1 and 2 we subtract the previous position from the current one, to find out what amount to pan the viewport by.
In line three we find the ratio our map is being displayed at, as when the map is zoomed, 1px in size is no longer 1px on the screen.
In the remaining lines we pan the window by the equivalent of the amount the vehicle moved.

Let's have a look what we have so far:

In part 1 we solved some issues with regard to coordinate projection, and built an example, that loads in coordinates from an xml file, and plots a vehicle's movement over a map.
In part 2 we added the high-definition maps that load more detailed areas, as the viewer zooms in:

The SVG file:
example4.svg (Opens in a new window)

The color-coded source-code:
example4.html

Well, that's about it for the 2002 paper - I hope you found it interesting, if you have any comments or questions don't hesitate to email me.

For SVG Open 2003, we have added part 3, SVG and Base64.


Cheers,
Richard Bennett.
richard.b@gritechnologies.com

Valid XHTML 1.0!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值