commit 57215a908ab74e3e9f5640bac2add2ff23a64c96
parent 813dca4b05e11924d7399279f1633919dd3b745b
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Fri, 3 Mar 2017 01:23:14 +0300
[canvas markers] refactored code, split big function drawTile
Diffstat:
1 file changed, 131 insertions(+), 120 deletions(-)
diff --git a/src/lib/leaflet.layer.canvasMarkers/index.js b/src/lib/leaflet.layer.canvasMarkers/index.js
@@ -152,41 +152,37 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
canvas.width = this.options.tileSize;
canvas.height = this.options.tileSize;
L.Util.requestAnimFrame(() => {
- this.drawTile(canvas, coords);
- done(null, canvas);
- });
+ this.drawTile(canvas, coords).then(() => done(null, canvas));
+ }
+ );
return canvas;
},
- drawTile: function(canvas, coords) {
- const
- zoom = coords.z,
- tileSize = this.options.tileSize,
- tileN = coords.y * tileSize,
- tileW = coords.x * tileSize,
- tileS = tileN + tileSize,
- tileE = tileW + tileSize;
+ selectMarkersForDraw: function({tileN, tileS, tileE, tileW}, zoom, withPaddings) {
+ // FIXME: padding should depend on options.iconScale and fontSize
+ if (!this._map) {
+ return {};
+ }
const
- iconsHorPad = 520,
- iconsVertPad = 50,
- labelsHorPad = 256,
- labelsVertPad = 20;
+ iconsHorPad = withPaddings ? 520 : 0,
+ iconsVertPad = withPaddings ? 50 : 0,
+ labelsHorPad = withPaddings ? 256 : 0,
+ labelsVertPad = withPaddings ? 20 : 0;
const
iconsBounds = L.latLngBounds(
- this._map.unproject([tileW - iconsHorPad, tileS + iconsHorPad], zoom),
- this._map.unproject([tileE + iconsHorPad, tileN - iconsVertPad], zoom)
+ this._map.unproject(L.point(tileW - iconsHorPad, tileS + iconsHorPad), zoom),
+ this._map.unproject(L.point(tileE + iconsHorPad, tileN - iconsVertPad), zoom)
),
labelsBounds = L.latLngBounds(
- this._map.unproject([tileW - labelsHorPad, tileS + labelsHorPad], zoom),
- this._map.unproject([tileE + labelsHorPad, tileN - labelsVertPad], zoom)
+ this._map.unproject(L.point(tileW - labelsHorPad, tileS + labelsHorPad), zoom),
+ this._map.unproject(L.point(tileE + labelsHorPad, tileN - labelsVertPad), zoom)
);
-
const
iconUrls = [],
markerJobs = {};
- const pointsForMarkers = this.rtree.search(
- {
+ // used only to preload icons
+ const pointsForMarkers = this.rtree.search({
minX: iconsBounds.getWest(),
minY: iconsBounds.getSouth(),
maxX: iconsBounds.getEast(),
@@ -194,13 +190,13 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
}
);
+ // used to place labels
const pointsForLabels = this.rtree.search({
minX: labelsBounds.getWest(), minY: labelsBounds.getSouth(),
maxX: labelsBounds.getEast(), maxY: labelsBounds.getNorth()
}
);
-
for (let marker of pointsForMarkers) {
const p = this._map.project(marker.latlng, zoom);
let icon = marker.icon;
@@ -211,101 +207,116 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
let markerId = L.stamp(marker);
markerJobs[markerId] = {marker: marker, icon: icon, projectedXY: p};
}
- this.preloadIcons(iconUrls).then(() => {
- if (!this._map) {
- return;
- }
- const textHeight = this.options.labelFontSize;
- if (this._labelPositionsZoom !== zoom) {
- this._labelPositionsZoom = zoom;
- this.resetLabels();
- }
- const ctx = canvas.getContext('2d');
- ctx.font = L.Util.template('bold {size}px {name}',
- {'name': this.options.labelFontName, 'size': this.options.labelFontSize}
- );
- for (let [markerId, job] of Object.entries(markerJobs)) {
- let img = this._images[job.icon.url];
- job.img = img;
- const imgW = Math.round(img.width * this.options.iconScale);
- const imgH = Math.round(img.height * this.options.iconScale);
- if (!(markerId in this._iconPositions)) {
- let x = job.projectedXY.x - job.icon.center[0] * this.options.iconScale;
- let y = job.projectedXY.y - job.icon.center[1] * this.options.iconScale;
- x = Math.round(x);
- y = Math.round(y);
- this._iconPositions[markerId] = [x, y];
- this._regions.insert({
- minX: x, minY: y, maxX: x + imgW, maxY: y + imgH,
- marker: job.marker, isLabel: false
- }
- );
+ return {iconUrls, markerJobs, pointsForLabels};
+ },
+
+ drawSelectedMarkers: function(canvas, pixelExtents, markerJobs, pointsForLabels, zoom) {
+ const {tileN, tileW, tileS, tileE} = pixelExtents;
+ const textHeight = this.options.labelFontSize;
+ if (this._labelPositionsZoom !== zoom) {
+ this._labelPositionsZoom = zoom;
+ this.resetLabels();
+ }
+ const ctx = canvas.getContext('2d');
+ ctx.font = L.Util.template('bold {size}px {name}',
+ {'name': this.options.labelFontName, 'size': this.options.labelFontSize * this.options.iconScale}
+ );
+ for (let [markerId, job] of Object.entries(markerJobs)) {
+ let img = this._images[job.icon.url];
+ job.img = img;
+ const imgW = Math.round(img.width * this.options.iconScale);
+ const imgH = Math.round(img.height * this.options.iconScale);
+ if (!(markerId in this._iconPositions)) {
+ let x = job.projectedXY.x - job.icon.center[0] * this.options.iconScale;
+ let y = job.projectedXY.y - job.icon.center[1] * this.options.iconScale;
+ x = Math.round(x);
+ y = Math.round(y);
+ this._iconPositions[markerId] = [x, y];
+ this._regions.insert({
+ minX: x, minY: y, maxX: x + imgW, maxY: y + imgH,
+ marker: job.marker, isLabel: false
}
- let [x, y] = this._iconPositions[markerId];
- job.iconCenter = [x + imgW / 2, y + imgH / 2];
- job.iconSize = [imgW, imgH];
+ );
+ }
+ let [x, y] = this._iconPositions[markerId];
+ job.iconCenter = [x + imgW / 2, y + imgH / 2];
+ job.iconSize = [imgW, imgH];
+ }
+ for (let marker of pointsForLabels) {
+ const markerId = L.stamp(marker);
+ const job = markerJobs[markerId];
+ let label = job.marker.label;
+ if (label) {
+ if (typeof label === 'function') {
+ label = label(job.marker);
}
- for (let marker of pointsForLabels) {
- const markerId = L.stamp(marker);
- const job = markerJobs[markerId];
- let label = job.marker.label;
- if (label) {
- if (typeof label === 'function') {
- label = label(job.marker);
+ job.label = label;
+ if (!(markerId in this._labelPositions)) {
+ const textWidth = ctx.measureText(label).width;
+ const p = this.findLabelPosition(job.iconCenter, job.iconSize, textWidth, textHeight);
+ this._labelPositions[markerId] = p;
+ let [x, y] = p;
+ this._regions.insert({
+ minX: x, minY: y, maxX: x + textWidth, maxY: y + textHeight,
+ marker: job.marker, isLabel: true
}
- job.label = label;
- if (!(markerId in this._labelPositions)) {
- const textWidth = ctx.measureText(label).width;
- const p = this.findLabelPosition(job.iconCenter, job.iconSize, textWidth, textHeight);
- this._labelPositions[markerId] = p;
- let [x, y] = p;
- this._regions.insert({
- minX: x, minY: y, maxX: x + textWidth, maxY: y + textHeight,
- marker: job.marker, isLabel: true
- }
- );
+ );
- }
- } else {
- this._labelPositions[markerId] = null;
- }
}
+ } else {
+ this._labelPositions[markerId] = null;
+ }
+ }
- const regionsInTile = this._regions.search({minX: tileW, minY: tileN, maxX: tileE, maxY: tileS});
- // draw labels
- for (let region of regionsInTile) {
- if (region.isLabel) {
- //TODO: set font name ant size in options
- const markerId = L.stamp(region.marker);
- const job = markerJobs[markerId];
- const p = this._labelPositions[markerId];
- const x = p[0] - tileW;
- const y = p[1] - tileN;
- ctx.textBaseline = 'bottom';
- ctx.shadowColor = '#fff';
- ctx.strokeStyle = '#fff';
- ctx.fillStyle = '#000';
- ctx.lineWidth = 1;
- ctx.shadowBlur = 2;
- ctx.strokeText(job.label, x, y + textHeight);
- ctx.shadowBlur = 0;
- ctx.fillText(job.label, x, y + textHeight);
- }
- }
- // draw icons
- for (let region of regionsInTile) {
- if (!region.isLabel) {
- const markerId = L.stamp(region.marker);
- const job = markerJobs[markerId];
- const p = this._iconPositions[markerId];
- const x = p[0] - tileW;
- const y = p[1] - tileN;
- ctx.drawImage(job.img, x, y, job.iconSize[0], job.iconSize[1]);
- }
- }
+ const regionsInTile = this._regions.search({minX: tileW, minY: tileN, maxX: tileE, maxY: tileS});
+ // draw labels
+ for (let region of regionsInTile) {
+ if (region.isLabel) {
+ //TODO: set font name ant size in options
+ const markerId = L.stamp(region.marker);
+ const job = markerJobs[markerId];
+ const p = this._labelPositions[markerId];
+ const x = p[0] - tileW;
+ const y = p[1] - tileN;
+ ctx.textBaseline = 'bottom';
+ ctx.shadowColor = '#fff';
+ ctx.strokeStyle = '#fff';
+ ctx.fillStyle = '#000';
+ ctx.lineWidth = 1;
+ ctx.shadowBlur = 2;
+ ctx.strokeText(job.label, x, y + textHeight);
+ ctx.shadowBlur = 0;
+ ctx.fillText(job.label, x, y + textHeight);
}
- );
- return this;
+ }
+ // draw icons
+ for (let region of regionsInTile) {
+ if (!region.isLabel) {
+ const markerId = L.stamp(region.marker);
+ const job = markerJobs[markerId];
+ const p = this._iconPositions[markerId];
+ const x = p[0] - tileW;
+ const y = p[1] - tileN;
+ ctx.drawImage(job.img, x, y, job.iconSize[0], job.iconSize[1]);
+ }
+ }
+ },
+
+ drawTile: async function(canvas, coords) {
+ const
+ zoom = coords.z,
+ tileSize = this.options.tileSize,
+ tileN = coords.y * tileSize,
+ tileW = coords.x * tileSize,
+ tileS = tileN + tileSize,
+ tileE = tileW + tileSize;
+ const pixelExtents = {tileN, tileS, tileE, tileW};
+ const {iconUrls, markerJobs, pointsForLabels} = this.selectMarkersForDraw(pixelExtents, zoom, true);
+ if (!markerJobs) {
+ return;
+ }
+ await this.preloadIcons(iconUrls);
+ this.drawSelectedMarkers(canvas, pixelExtents, markerJobs, pointsForLabels, zoom);
},
resetLabels: function() {
@@ -318,9 +329,10 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
if (!e.latlng) {
return;
}
- var p = this._map.project(e.latlng),
- region = this._regions.search({minX: p.x, minY: p.y, maxX: p.x, maxY: p.y})[0],
- marker;
+ const
+ p = this._map.project(e.latlng),
+ region = this._regions.search({minX: p.x, minY: p.y, maxX: p.x, maxY: p.y})[0];
+ let marker;
if (region) {
marker = region.marker;
} else {
@@ -330,7 +342,7 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
},
onMouseMove: function(e) {
- var marker = this.findMarkerFromMouseEvent(e);
+ const marker = this.findMarkerFromMouseEvent(e);
if (this._hoverMarker !== marker) {
if (this._hoverMarker) {
this.fire('markerleave', {marker: this._hoverMarker});
@@ -343,11 +355,10 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
},
showTooltip: function(e) {
- var text;
if (!e.marker.tooltip) {
return;
}
- text = e.marker.tooltip;
+ let text = e.marker.tooltip;
if (typeof text === 'function') {
text = text(e.marker);
if (!e.marker.tooltip) {
@@ -355,7 +366,7 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
}
}
this.toolTip.innerHTML = text;
- var p = this._map.latLngToLayerPoint(e.marker.latlng);
+ const p = this._map.latLngToLayerPoint(e.marker.latlng);
L.DomUtil.setPosition(this.toolTip, p);
L.DomUtil.addClass(this.toolTip, 'canvas-marker-tooltip-on');
},
@@ -379,7 +390,7 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
},
onClick: function(e) {
- var marker = this.findMarkerFromMouseEvent(e);
+ const marker = this.findMarkerFromMouseEvent(e);
if (marker) {
L.extend(e, {marker: marker});
this.fire('markerclick', e);
@@ -387,7 +398,7 @@ L.Layer.CanvasMarkers = L.GridLayer.extend({
},
onRightClick: function(e) {
- var marker = this.findMarkerFromMouseEvent(e);
+ const marker = this.findMarkerFromMouseEvent(e);
if (marker) {
L.extend(e, {marker: marker});
this.fire('markercontextmenu', e);