commit 6aab86b171715187613137d82ad134b26cde58da
parent 695cab214830324b03bf7bb1bcdef76529f17149
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Sat, 18 Mar 2017 00:46:38 +0300
[print] added option to overlay magnetic meridians
Diffstat:
5 files changed, 179 insertions(+), 9 deletions(-)
diff --git a/src/lib/leaflet.control.printPages/control.js b/src/lib/leaflet.control.printPages/control.js
@@ -14,6 +14,7 @@ import {blobFromString} from 'lib/binary-strings';
import 'lib/leaflet.hashState/leaflet.hashState';
import 'lib/leaflet.control.commons';
import logging from 'lib/logging';
+import {MagneticMeridians} from './decoration.magnetic-meridians';
ko.extenders.checkNumberRange = function(target, range) {
return ko.pureComputed({
@@ -79,12 +80,16 @@ L.Control.PrintPages = L.Control.extend({
this.pageSizeDescription = ko.pureComputed(this._displayPageSize, this);
this.pagesNum = ko.observable(0);
this.pagesNumLabel = ko.pureComputed(this._pagesNumLabel, this);
+ this.gridOn = ko.observable(false);
+ this.magneticMerisiansdOn = ko.observable(false);
//hash state notifications
this.scale.subscribe(this.notifyChange, this);
this.printSize.subscribe(this.notifyChange, this);
this.resolution.subscribe(this.notifyChange, this);
this.zoomLevel.subscribe(this.notifyChange, this);
+ this.gridOn.subscribe(this.notifyChange, this);
+ this.magneticMerisiansdOn.subscribe(this.notifyChange, this);
},
onAdd: function(map) {
@@ -200,12 +205,17 @@ L.Control.PrintPages = L.Control.extend({
}
);
const resolution = this.resolution();
+ const decorationLayers = [];
+ if (this.magneticMerisiansdOn()) {
+ decorationLayers.push(new MagneticMeridians());
+ }
renderPages({
map: this._map,
pages,
zooms: this.zoomForPrint(),
resolution,
scale: this.scale(),
+ decorationLayers,
progressCallback: this.incrementProgress.bind(this)
}
).then((images) => {
@@ -226,6 +236,10 @@ L.Control.PrintPages = L.Control.extend({
latLngBounds: page.getLatLngBounds(),
printSize: page.getPrintSize()
}];
+ const decorationLayers = [];
+ if (this.magneticMerisiansdOn()) {
+ decorationLayers.push(new MagneticMeridians());
+ }
this.downloadProgressRange(1000);
this.downloadProgressDone(undefined);
this.makingPdf(true);
@@ -235,6 +249,7 @@ L.Control.PrintPages = L.Control.extend({
zooms: this.zoomForPrint(),
resolution: this.resolution(),
scale: this.scale(),
+ decorationLayers,
progressCallback: this.incrementProgress.bind(this)
}
)
@@ -392,6 +407,11 @@ L.Control.PrintPages = L.Control.extend({
state.push(latLng.lng.toFixed(5));
state.push(page._rotated ? '1' : '0');
}
+ let flags =
+ (this.magneticMerisiansdOn() ? 1 : 0) |
+ (this.gridOn() ? 2 : 0);
+ state.push(flags);
+
}
return state;
},
@@ -421,6 +441,13 @@ L.Control.PrintPages = L.Control.extend({
}
this.addPage(!!rotated, L.latLng(lat, lng));
}
+ if (state.length) {
+ const flags = parseInt(state.shift(), 10);
+ if (flags >= 0 && flags <= 3) {
+ this.magneticMerisiansdOn(!!(flags & 1));
+ this.gridOn(!!(flags & 2));
+ }
+ }
return true;
}
}
diff --git a/src/lib/leaflet.control.printPages/decoration.magnetic-meridians.js b/src/lib/leaflet.control.printPages/decoration.magnetic-meridians.js
@@ -0,0 +1,89 @@
+import L from 'leaflet';
+import {getDeclination} from 'lib/magnetic-declination';
+import {PrintStaticLayer} from './decorations';
+
+function radians(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function movePoint(p, angle, dist) {
+ angle = radians(angle);
+ return new L.point(p.x + Math.sin(angle) * dist, p.y - Math.cos(angle) * dist);
+}
+
+class MagneticMeridians extends PrintStaticLayer {
+ lineThicknessMm = 0.2;
+ lineIntervalMm = 50;
+ samplingIntervalMm = 15;
+ color = '#99d5ff';
+
+ _makeCanvasToLatLngTransformer(printOptions) {
+ const projectedBounds = printOptions.pixelBounds;
+ const scale = projectedBounds.getSize().unscaleBy(printOptions.destPixelSize);
+ const origin = projectedBounds.min;
+ return function(pixel) {
+ return L.CRS.EPSG3857.pointToLatLng(pixel.scaleBy(scale).add(origin), printOptions.zoom);
+ }
+ };
+
+ _drawRaster(canvas, printOptions) {
+ const toLatLng = this._makeCanvasToLatLngTransformer(printOptions);
+ const ctx = canvas.getContext('2d');
+ ctx.strokeStyle = this.color;
+ ctx.lineWidth = this.lineThicknessMm / 25.4 * printOptions.resolution;
+ const intervalPx = this.lineIntervalMm / 25.4 * printOptions.resolution;
+ const samplingPx = this.samplingIntervalMm / 25.4 * printOptions.resolution;
+ const pageDiagonal = Math.sqrt(printOptions.destPixelSize.x * printOptions.destPixelSize.x + printOptions.destPixelSize.y * printOptions.destPixelSize.y);
+ const maxSegments = pageDiagonal / 2 / samplingPx;
+
+ function drawLine(p, directionDown) {
+ ctx.moveTo(p.x, p.y);
+
+ for (let i = 0; i <= maxSegments; i++) {
+ let latLng = toLatLng(p);
+ let declination = getDeclination(latLng.lat, latLng.lng);
+ if (declination === null) {
+ break;
+ }
+ if (directionDown) {
+ declination += 180;
+ }
+ p = movePoint(p, declination, samplingPx);
+ ctx.lineTo(p.x, p.y);
+ }
+ }
+
+ const center = printOptions.destPixelSize.divideBy(2);
+ const maxLines = pageDiagonal / 2 / intervalPx;
+
+ drawLine(center);
+ drawLine(center, true);
+
+ let p = center;
+ for (let i = 0; i <= maxLines; i++) {
+ let latLng = toLatLng(p);
+ let declination = getDeclination(latLng.lat, latLng.lng);
+ if (declination === null) {
+ declination = 0;
+ }
+ p = movePoint(p, declination + 90, intervalPx);
+ drawLine(p);
+ drawLine(p, true);
+ }
+ p = center;
+ for (let i = 0; i <= maxLines; i++) {
+ let latLng = toLatLng(p);
+ let declination = getDeclination(latLng.lat, latLng.lng);
+ if (declination === null) {
+ declination = 0;
+ }
+ p = movePoint(p, declination - 90, intervalPx);
+ drawLine(p);
+ drawLine(p, true);
+ }
+
+ ctx.stroke();
+ }
+}
+
+export {MagneticMeridians};
diff --git a/src/lib/leaflet.control.printPages/decorations.js b/src/lib/leaflet.control.printPages/decorations.js
@@ -0,0 +1,41 @@
+class PrintStaticLayer {
+ _layerDummy = true;
+ _printProgressWeight = 0.01;
+
+ cloneForPrint() {
+ return this;
+ };
+
+ // printOptions = {
+ // xhrOptions,
+ // pixelBounds,
+ // latLngBounds,
+ // destPixelSize,
+ // resolution,
+ // scale,
+ // zoom
+ // }
+ async getTilesInfo(printOptions) {
+ return {
+ iterateTilePromises: (function*() {
+ yield {
+ tilePromise: Promise.resolve({
+ draw: (canvas) => this._drawRaster(canvas, printOptions),
+ isOverlay: true,
+ overlaySolid: false
+ }
+ ),
+ abortLoading: () => {
+ }
+ }
+ }).bind(this),
+ count: 1
+ };
+ }
+
+ _drawRaster(canvas, printOptions) {
+ return;
+ }
+}
+
+export {PrintStaticLayer};
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.printPages/form.html b/src/lib/leaflet.control.printPages/form.html
@@ -65,6 +65,12 @@
</select>
</td>
</tr>
+ <tr>
+ <td colspan="2">
+ <label><input type="checkbox" data-bind="checked: magneticMerisiansdOn"> Magnetic meridians</label>
+ <label><input type="checkbox" data-bind="checked: gridOn"> Kilometers grid</label>
+ </td>
+ </tr>
<tr><td colspan="2">
<a class="button-settings image-button" data-bind="click: function() {settingsExpanded(!settingsExpanded())}"
title="More settings"></a>
diff --git a/src/lib/leaflet.control.printPages/map-render.js b/src/lib/leaflet.control.printPages/map-render.js
@@ -180,7 +180,7 @@ async function* iterateLayersTiles(layers, latLngBounds, destPixelSize, resoluti
let doStop;
for (let layer of layers) {
let zoom;
- if (layer.options.scaleDependent) {
+ if (layer.options && layer.options.scaleDependent) {
zoom = zooms.mapZoom;
} else {
zoom = zooms.satZoom;
@@ -189,8 +189,11 @@ async function* iterateLayersTiles(layers, latLngBounds, destPixelSize, resoluti
L.CRS.EPSG3857.latLngToPoint(latLngBounds.getNorthWest(), zoom).round(),
L.CRS.EPSG3857.latLngToPoint(latLngBounds.getSouthEast(), zoom).round()
);
- let map = getTempMap(zoom, layer._rasterizeNeedsFullSizeMap, pixelBounds);
- map.addLayer(layer);
+ let map;
+ if (!layer._layerDummy) {
+ map = getTempMap(zoom, layer._rasterizeNeedsFullSizeMap, pixelBounds);
+ map.addLayer(layer);
+ }
let {iterateTilePromises, count} = await layer.getTilesInfo({
xhrOptions: defaultXHROptions,
pixelBounds,
@@ -213,11 +216,13 @@ async function* iterateLayersTiles(layers, latLngBounds, destPixelSize, resoluti
break;
}
}
- if (doStop) {
- disposeMap(map);
- break;
- } else {
- Promise.all(layerPromises).then(() => disposeMap(map));
+ if (!layer._layerDummy) {
+ if (doStop) {
+ disposeMap(map);
+ break;
+ } else {
+ Promise.all(layerPromises).then(() => disposeMap(map));
+ }
}
}
}
@@ -253,9 +258,10 @@ async function* promiseQueueBuffer(source, maxActive) {
}
-async function renderPages({map, pages, zooms, resolution, scale, progressCallback}) {
+async function renderPages({map, pages, zooms, resolution, scale, progressCallback, decorationLayers}) {
const xhrQueue = new XHRQueue();
const layers = getLayersForPrint(map, xhrQueue);
+ layers.push(...decorationLayers);
let progressRange = 0;
for (let layer of layers) {
progressRange += layer._printProgressWeight || 1;