+var gTrackLayer = {
+ context: null,
+ curPosMapCache: undefined,
+ lastDrawnPoint: null,
+ drawing: false,
+
+ drawTrack: function() {
+ if (gTrackLayer.drawing) { return; }
+ gTrackLayer.drawing = true;
+ //performance.now()
+ if (gTrackLayer.context && (document.hidden != true)) { // Only draw if we're actually visible.
+ gTrackLayer.lastDrawnPoint = null;
+ gTrackLayer.curPosMapCache = undefined;
+ gTrackLayer.context.clearRect(0, 0, gTrackCanvas.width, gTrackCanvas.height);
+ if (gTrack.length) {
+ for (var i = 0; i < gTrack.length; i++) {
+ gTrackLayer.drawTrackPoint(gTrack[i].coords.latitude, gTrack[i].coords.longitude,
+ (i + 1 >= gTrack.length || gTrack[i+1].beginSegment));
+ }
+ }
+ }
+ gTrackLayer.drawing = false;
+ },
+
+ drawTrackPoint: function(aLatitude, aLongitude, aLastPoint) {
+ var trackpoint = {"worldpos": gps2xy(aLatitude, aLongitude)};
+ var update_drawnpoint = true;
+ // lastPoint is for optimizing (not actually executing the draw until the last)
+ trackpoint.segmentEnd = (aLastPoint === true);
+ trackpoint.optimized = (aLastPoint === false);
+ trackpoint.mappos = {x: Math.round((trackpoint.worldpos.x - gMap.pos.x) / gMap.zoomFactor + gMap.width / 2),
+ y: Math.round((trackpoint.worldpos.y - gMap.pos.y) / gMap.zoomFactor + gMap.height / 2)};
+ trackpoint.skip_drawing = false;
+ if (gTrackLayer.lastDrawnPoint) {
+ // Lines completely outside the current display should not be drawn.
+ if ((trackpoint.mappos.x < 0 && gTrackLayer.lastDrawnPoint.mappos.x < 0) ||
+ (trackpoint.mappos.x > gMap.width && gTrackLayer.lastDrawnPoint.mappos.x > gMap.width) ||
+ (trackpoint.mappos.y < 0 && gTrackLayer.lastDrawnPoint.mappos.y < 0) ||
+ (trackpoint.mappos.y > gMap.height && gTrackLayer.lastDrawnPoint.mappos.y > gMap.height)) {
+ trackpoint.skip_drawing = true;
+ }
+ }
+ if (!gTrackLayer.lastDrawnPoint || !gTrackLayer.lastDrawnPoint.optimized) {
+ gTrackLayer.context.strokeStyle = gTrackColor;
+ gTrackLayer.context.fillStyle = gTrackLayer.context.strokeStyle;
+ gTrackLayer.context.lineWidth = gTrackWidth;
+ gTrackLayer.context.lineCap = "round";
+ gTrackLayer.context.lineJoin = "round";
+ }
+ // This breaks optimiziation, so make sure to reset optimization.
+ if (trackpoint.skip_drawing || !gTrackLayer.lastDrawnPoint) {
+ trackpoint.optimized = false;
+ // Close path if one was open.
+ if (gTrackLayer.lastDrawnPoint && gTrackLayer.lastDrawnPoint.optimized) {
+ gTrackLayer.context.stroke();
+ }
+ }
+ if (!trackpoint.skip_drawing) {
+ if (gTrackLayer.lastDrawnPoint && gTrackLayer.lastDrawnPoint.skip_drawing && !gTrackLayer.lastDrawnPoint.segmentEnd) {
+ // If the last point was skipped but the current one isn't, draw a segment start
+ // for the off-screen previous one as well as a connection line.
+ gTrackLayer.context.beginPath();
+ gTrackLayer.context.arc(gTrackLayer.lastDrawnPoint.mappos.x, gTrackLayer.lastDrawnPoint.mappos.y,
+ gTrackLayer.context.lineWidth, 0, Math.PI * 2, false);
+ gTrackLayer.context.fill();
+ gTrackLayer.context.lineTo(trackpoint.mappos.x, trackpoint.mappos.y);
+ }
+ else if (!gTrackLayer.lastDrawnPoint || !gTrackLayer.lastDrawnPoint.optimized) {
+ // Start drawing a segment with the current point.
+ gTrackLayer.context.beginPath();
+ gTrackLayer.context.arc(trackpoint.mappos.x, trackpoint.mappos.y,
+ gTrackLayer.context.lineWidth, 0, Math.PI * 2, false);
+ gTrackLayer.context.fill();
+ }
+ else if (!trackpoint.segmentEnd && gTrackLayer.lastDrawnPoint &&
+ (Math.abs(gTrackLayer.lastDrawnPoint.mappos.x - trackpoint.mappos.x) <= 1) &&
+ (Math.abs(gTrackLayer.lastDrawnPoint.mappos.y - trackpoint.mappos.y) <= 1)) {
+ // We would draw the same or almost the same point, don't do any actual drawing.
+ update_drawnpoint = false;
+ }
+ else {
+ // Continue drawing segment, close if needed.
+ gTrackLayer.context.lineTo(trackpoint.mappos.x, trackpoint.mappos.y);
+ if (!trackpoint.optimized)
+ gTrackLayer.context.stroke();
+ }
+ }
+ if (update_drawnpoint) {
+ gTrackLayer.lastDrawnPoint = trackpoint;
+ }
+ },
+
+ drawCurrentLocation: function(trackPoint) {
+ var locpoint = gps2xy(trackPoint.coords.latitude, trackPoint.coords.longitude);
+ var circleRadius = Math.round(gCurLocSize / 2);
+ var mappos = {x: Math.round((locpoint.x - gMap.pos.x) / gMap.zoomFactor + gMap.width / 2),
+ y: Math.round((locpoint.y - gMap.pos.y) / gMap.zoomFactor + gMap.height / 2)};
+
+ gTrackLayer.undrawCurrentLocation();
+
+ // Cache overdrawn area.
+ gTrackLayer.curPosMapCache =
+ {point: locpoint,
+ radius: circleRadius,
+ data: gTrackLayer.context.getImageData(mappos.x - circleRadius,
+ mappos.y - circleRadius,
+ circleRadius * 2, circleRadius * 2)};
+
+ gTrackLayer.context.strokeStyle = gCurLocColor;
+ gTrackLayer.context.fillStyle = gTrackLayer.context.strokeStyle;
+ gTrackLayer.context.beginPath();
+ gTrackLayer.context.arc(mappos.x, mappos.y,
+ circleRadius, 0, Math.PI * 2, false);
+ gTrackLayer.context.fill();
+ },
+
+ undrawCurrentLocation: function() {
+ if (gTrackLayer.curPosMapCache) {
+ var oldpoint = gTrackLayer.curPosMapCache.point;
+ var oldmp = {x: Math.round((oldpoint.x - gMap.pos.x) / gMap.zoomFactor + gMap.width / 2),
+ y: Math.round((oldpoint.y - gMap.pos.y) / gMap.zoomFactor + gMap.height / 2)};
+ gTrackLayer.context.putImageData(gTrackLayer.curPosMapCache.data,
+ oldmp.x - gTrackLayer.curPosMapCache.radius,
+ oldmp.y - gTrackLayer.curPosMapCache.radius);
+ gTrackLayer.curPosMapCache = undefined;
+ }