Improving khtml.maplib

Its general purpose is to improve the OpenSource JavaScript Slippy WebMap Library khtml.maplib.

As this GSoC-project is already finished, this site will not be maintained any more. The API and the code for khtml.maplib may still change, so please see Simple_marker_API for more up to date information or the JSdoc API-documentation that comes in the tar-ball with khtml.maplib.

Preliminary work

Update 2: June 30th

Due to heavy workload on other projects at university, I could not start as early as planned, but now as all my exams are over, I am already really into coding and testing.
I am now about 2 weeks behind the planned timeline.

I used khtml.maplib for another project at my university. It is called SharedPainting and a form of collaborative painting tool. khtml is used for pinch/zoom navigation in the PaintingOverview. Each drawing-area is one tile in the form of map-tiles. Therefore I crawled really deep into the sourcecode of khtml and found nearly by chance some bugs, that I fixed.

If you are interested, goto SharedPainting with you iPhone or iPod touch.

Only on touchscreen-devices! Zoom in to maximum zoomlevel with two fingers and watch the map jumping.

Again with touch-zooming and panning. When you first use one finger to drag the map, then apply a second one to zoom and then release one finger and continue dragging with the other one, the map stays still and does not move any more.

I located the problem here:

this.end=function(evt){

if(evt.preventDefault){

evt.preventDefault();// The W3C DOM way

}else{

evt.returnValue=false;// The IE way

}

window.clearInterval(this.zoomOutInterval);

this.zoomOutStarted=false;

this.zoomOutSpeed=0.01;

if(evt.touches.length==0){

this.moveok=true;

if(this.moveAnimationMobile){

if(this.moveAnimationBlocked==false){

var speedX =this.lastMoveX-this.moveX;

var speedY =this.lastMoveY-this.moveY;

clearTimeout(this.animateMoveTimeout);

this.animateMove(speedX, speedY);

}

}

}

}

I added this to avoid the problem. It's the same calculation that is done, when a second finger touches the screen, but now I also do it, when the second finger is removed.

Only on touchscreen-devices! Drag with one finger, then apply the second one to zoom and then release one finger and try dragging.

When double-tap zooming on a map that's not fullscreen, but only a part of the screen, the map doesn't calculate the offsetLeft and offsetTop of the map and so often zooms the tapped point out of the view, especially when it's near the edge.

First I started to analyze the existing marker interface and soon found out, that using 2 divs where the marker is placed in, is 1 too much (source code). I started playing around with the code and very soon got a working version with only one div (source code).

For testing and comparing the performance of the different maps, I found some nice codes on mappertests.codeplex.com, which I took and modified a little bit, to meet my requirements.

Try the two versions with many markers (>1000) and see the difference in the time:

And I decided to embed it as standard marker via data-URI, base 64 directly in the source code. This tool helped me with that.

But since IE6 and IE7 don't support data-URI, I had to do a workaround and provide the images as separate files as well (IE8 works with data-URI).

IE6 also has problems with transparent PNGs, so I had to do another workaround for that. I tried a special "filter"-method Microsoft provides for this case (see here). It worked pretty well, displaying the marker and background on the monitor, but when trying to print the map, the transparent parts went black.

This is what Google did, now see what it looks like, when you try to print a map on IE6:

I didn't want to look for another workaround for the workaround, so I decided, to create separate files with reduced quality (IE6 supports transparency in 256 color images):

They are not the prettiest, but at least they still look good, when you print the map. All other browsers do get the high-res version.

I also added some nice cursors which make it more fun to use, than the normal pointer.

Cursors

At Google Maps, Bing and Yahoo Maps you can see, that they all use this nice little finger, hand and fist mousecursor in the map, when dragging it and hovering over an UI-element or a marker.

I also tried to implement this cursors, which is quite easy if you only work on one browser. But if you start testing it with another one, you will always find a new situation, that you hadn't considered before and that needs a special workaround.

Therefore I did a lot of testing with events, and this page helped me to understand the difference between capturing and bubbeling phase.

The cursor files for the Internet Explorer, I created with the help of the screenzoom on my mac and a little software called JustCursors.

So far I successfully tested the cursors on Firefox 3.6, Safari 5 and Chrome 12. IE6 and IE8 still have some small bugs, that I am working on.

Other browser are still to be tested. If you find any bugs, please tell me!

Update 4: July 14th

This week I improved the cursors I implemented last week and I also implemented a first infobox based on HTML5 into khtml.maplib.
With this progress I think I can say that have caught up with the original timeplan.

Cursors

I did some more improvement on the cursor-code and successfully tested it on IE6 & IE8.

Therefore I had to do a little workaround for the standardmarker, because IE has troubles with the shape area.

I also took out the shape area for touch devices (tested in iPhone 4 and iPad 1 so far), to make the markers better grabbable with the finger.

Infobox

Google has again by far the most complicated approach, breaking their infowindow in more than 20 divs styling it with sprites and a nice shadow. But their infowindow also has the most aesthetics compared to the others.

My first approach to the infobox is using HTML5. Of course I am aware that it will not work on older browsers, but I want to concentrate on the core-functionality first and try to improve it later.

The pointer and the close-cross are embedded images again to save http-requests (again this will not work on older browsers, but I will deal with that later):

The rest of the infobox is done with a div with round-corners.

One special thing about the infobox is, that it can be opened on any object on the map, not only markers. Therefore the object only has to provide a position property and maybe a pixelOffset for this position.

An infobox can also be attached to a position without any object.

This works pretty nice as you can see here (click on a marker to open the according infobox).

This was pretty easy for desktop-browsers, but I was facing some problems on touch devices:

The infobox could not be opened, because the click-event was suppressed by the map. So I had to do a manual click-detection with touchstart- and touchend-events.

The close-cross was too small to be touched with a finger, so I had to display it larger on touch-devices.

So you can see it is working, but there are still improvements to make:

graphics for non-HTML5 browsers

create a shadow for infobox

re-centering map when opening infobox

rendering of infobox when moving marker with opened box

prevent unwanted opens of infobox

Update 5: July 21nd

This week I added the feature to move the map, when dragging a marker to the edge.

Marker

I was facing some minor troubles with the rendering function of the marker. With the old one, the dragged marker was flickering heavily when the map was moved.

The reason was, that the new pixel-coordinates of the dragged marker were always calculated from the gps-coordinates and that was too slow when the map was moved. So I had to differ in the rendering-function between the marker that is currently dragged and the other ones and do a different calculation for the pixel-coordinates.

Here are the two versions. Grab a marker and drag it to the edge of the map to see the difference.

Update 7: August 4th

This week I worked on the layout of the infobox to make it compatible to non-HTML5 browsers.

Infobox & Markers

Here are the two versions. The first one is a single HTML5-div with border-radius, the second one consists of 9 divs for edges and corners with an embedded graphic to make the infobox good looking on older browsers. I also removed all of the innerHTML-statements for security reasons and replaced them with standard DOM-manipulation.

I also did a rework on the mapmove-function when dragging a marker to an edge due to bad usability test. The map moved to fast, so I changed the function that it does not increment the speed to a fixed value, but that the speed the map moves depends on the distance of the marker to the edge. The nearer you drag it to the edge, the faster the map moves.

Marker

If you look at the source-code, you may notice that they are now pretty much the same. Together with my mentor I decided to use the same parameters to make it easy to port the code from google markers to khtml.maplib. You can now use the code directly from sites like this.

This is what it looks like:

var point =new mr.LatLng(50.875311,0.351563);

var image =new khtml.maplib.overlay.MarkerImage('marker-images/image.png',// url to imagenew khtml.maplib.Size(20,20),// size of the imagenew khtml.maplib.Point(0,0),// origin in a spritenew khtml.maplib.Point(10,20)// anchorpoint on the map);

var shadow =new khtml.maplib.overlay.MarkerImage('marker-images/shadow.png',// url to imagenew khtml.maplib.Size(34,20),// size of the imagenew khtml.maplib.Point(0,0),// origin in a spritenew khtml.maplib.Point(10,20)// anchorpoint on the map);