nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

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:
Msrc/lib/leaflet.control.printPages/control.js | 27+++++++++++++++++++++++++++
Asrc/lib/leaflet.control.printPages/decoration.magnetic-meridians.js | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/leaflet.control.printPages/decorations.js | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/leaflet.control.printPages/form.html | 6++++++
Msrc/lib/leaflet.control.printPages/map-render.js | 24+++++++++++++++---------
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;