Add graticule (from previous PR)
This commit is contained in:
parent
fda5fefc1e
commit
244e044d3f
@ -1,7 +1,8 @@
|
|||||||
### Change Log for Node-RED Worldmap
|
### Change Log for Node-RED Worldmap
|
||||||
|
|
||||||
|
- v2.0.1-beta - Add optional graticule
|
||||||
- v2.0.0-beta - Move to leaflet 1.4.x plus all plugins updated
|
- v2.0.0-beta - Move to leaflet 1.4.x plus all plugins updated
|
||||||
- v1.5.40 - Only enable on.location function when not in an iframe. Tidy html.
|
- v1.5.40 - Only enable on.location function when not in an iframe. Issue #89. Tidy html.
|
||||||
- v1.5.39 - Add weather-lite icons
|
- v1.5.39 - Add weather-lite icons
|
||||||
- v1.5.38 - Add Esri dark grey and ocean, re-add hikebike, layers
|
- v1.5.38 - Add Esri dark grey and ocean, re-add hikebike, layers
|
||||||
- v1.5.37 - Add .trackpoints to override default number in tracks node. Let tracks optionally be on different layers. Fix marker changing layers Issue #85
|
- v1.5.37 - Add .trackpoints to override default number in tracks node. Let tracks optionally be on different layers. Fix marker changing layers Issue #85
|
||||||
|
15
README.md
15
README.md
@ -9,8 +9,9 @@ map web page for plotting "things" on.
|
|||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
|
||||||
|
- v2.0.1-beta - Add optional graticule
|
||||||
- v2.0.0-beta - Move to leaflet 1.4.x plus all plugins updated
|
- v2.0.0-beta - Move to leaflet 1.4.x plus all plugins updated
|
||||||
- v1.5.40 - Only enable on.location function when not in an iframe. Tidy html.
|
- v1.5.40 - Only enable on.location function when not in an iframe. Issue #89. Tidy html.
|
||||||
- v1.5.39 - Add weather-lite icons
|
- v1.5.39 - Add weather-lite icons
|
||||||
- v1.5.38 - Add Esri dark grey and ocean, re-add hikebike, layers
|
- v1.5.38 - Add Esri dark grey and ocean, re-add hikebike, layers
|
||||||
- v1.5.37 - Add .trackpoints to override default in tracks node. Let tracks optionally be on different layers. Fix marker changing layers Issue #85
|
- v1.5.37 - Add .trackpoints to override default in tracks node. Let tracks optionally be on different layers. Fix marker changing layers Issue #85
|
||||||
@ -439,6 +440,18 @@ in a function node:
|
|||||||
opt: { opacity:0.8, attribution:"© University of Texas" }
|
opt: { opacity:0.8, attribution:"© University of Texas" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#### To add a Lat/Lon Graticule overlay
|
||||||
|
|
||||||
|
A graticule can be enabled via the node configuration, and can also be set dynamically,
|
||||||
|
for example in a function node:
|
||||||
|
|
||||||
|
msg.payload = { command : { grid : {
|
||||||
|
showgrid: true,
|
||||||
|
opt: { showLabel:true, dashArray:[5, 5], fontColor:"#900" }
|
||||||
|
};
|
||||||
|
|
||||||
|
see https://github.com/cloudybay/leaflet.latlng-graticule for more details about options and demo.
|
||||||
|
|
||||||
#### To clear all markers from a layer, or an overlay from the map
|
#### To clear all markers from a layer, or an overlay from the map
|
||||||
|
|
||||||
msg.payload.command.clear = "name of your layer/overlay to remove";
|
msg.payload.command.clear = "name of your layer/overlay to remove";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-web-worldmap",
|
"name": "node-red-contrib-web-worldmap",
|
||||||
"version": "2.0.0-beta",
|
"version": "2.0.1-beta",
|
||||||
"description": "A Node-RED node to provide a web page of a world map for plotting things on.",
|
"description": "A Node-RED node to provide a web page of a world map for plotting things on.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cgi": "0.3.1",
|
"cgi": "0.3.1",
|
||||||
|
@ -95,6 +95,11 @@
|
|||||||
<option value="deg">Degrees</option>
|
<option value="deg">Degrees</option>
|
||||||
<option value="dms">D.M.S</option>
|
<option value="dms">D.M.S</option>
|
||||||
</select>
|
</select>
|
||||||
|
<i class="fa fa-th" style="margin-left:22px;"></i> Graticule
|
||||||
|
<select id="node-input-showgrid" style="width:95px;">
|
||||||
|
<option value="false">Not shown</option>
|
||||||
|
<option value="true">Visible</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-path"><i class="fa fa-globe"></i> Web Path</label>
|
<label for="node-input-path"><i class="fa fa-globe"></i> Web Path</label>
|
||||||
@ -173,6 +178,7 @@ then by default <code>⌘⇧m</code> - <code>ctrl-shift-m</code> will load the m
|
|||||||
zoomlock: {value:"false"},
|
zoomlock: {value:"false"},
|
||||||
hiderightclick: {value:"false"},
|
hiderightclick: {value:"false"},
|
||||||
coords: {value:"false"},
|
coords: {value:"false"},
|
||||||
|
showgrid: {value:"false"},
|
||||||
path: {value:"/worldmap"}
|
path: {value:"/worldmap"}
|
||||||
},
|
},
|
||||||
inputs:1,
|
inputs:1,
|
||||||
|
@ -40,6 +40,7 @@ module.exports = function(RED) {
|
|||||||
this.panit = n.panit || "false";
|
this.panit = n.panit || "false";
|
||||||
this.hiderightclick = n.hiderightclick || "false";
|
this.hiderightclick = n.hiderightclick || "false";
|
||||||
this.coords = n.coords || "none";
|
this.coords = n.coords || "none";
|
||||||
|
this.showgrid = n.showgrid || "false";
|
||||||
this.path = n.path || "/worldmap";
|
this.path = n.path || "/worldmap";
|
||||||
if (this.path.charAt(0) != "/") { this.path = "/" + this.path; }
|
if (this.path.charAt(0) != "/") { this.path = "/" + this.path; }
|
||||||
if (!sockets[this.path]) {
|
if (!sockets[this.path]) {
|
||||||
@ -72,6 +73,7 @@ module.exports = function(RED) {
|
|||||||
c.panlock = node.panlock;
|
c.panlock = node.panlock;
|
||||||
c.zoomlock = node.zoomlock;
|
c.zoomlock = node.zoomlock;
|
||||||
c.showlayers = node.layers;
|
c.showlayers = node.layers;
|
||||||
|
c.grid = {showgrid:node.showgrid};
|
||||||
c.hiderightclick = node.hiderightclick;
|
c.hiderightclick = node.hiderightclick;
|
||||||
c.coords = node.coords;
|
c.coords = node.coords;
|
||||||
client.write(JSON.stringify({command:c}));
|
client.write(JSON.stringify({command:c}));
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
<script src="leaflet/OSMBuildings-Leaflet.js"></script>
|
<script src="leaflet/OSMBuildings-Leaflet.js"></script>
|
||||||
<script src="leaflet/leaflet-omnivore.min.js"></script>
|
<script src="leaflet/leaflet-omnivore.min.js"></script>
|
||||||
<script src="leaflet/Leaflet.coordinates.js"></script>
|
<script src="leaflet/Leaflet.coordinates.js"></script>
|
||||||
|
<script src="leaflet/leaflet.latlng-graticule.js"></script>
|
||||||
|
|
||||||
<script src="leaflet/dialog-polyfill.js"></script>
|
<script src="leaflet/dialog-polyfill.js"></script>
|
||||||
<script src="images/emoji.js"></script>
|
<script src="images/emoji.js"></script>
|
||||||
@ -274,6 +275,20 @@ else {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add graticule
|
||||||
|
var showGrid = false;
|
||||||
|
var Lgrid = L.latlngGraticule({
|
||||||
|
font: "Verdana",
|
||||||
|
fontColor: "#666",
|
||||||
|
zoomInterval: [
|
||||||
|
{start: 2, end: 2, interval: 40},
|
||||||
|
{start: 3, end: 3, interval: 20},
|
||||||
|
{start: 4, end: 4, interval: 10},
|
||||||
|
{start: 5, end: 7, interval: 5},
|
||||||
|
{start: 8, end: 20, interval: 1}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
if (!inIframe) {
|
if (!inIframe) {
|
||||||
// Add the fullscreen button
|
// Add the fullscreen button
|
||||||
L.control.fullscreen().addTo(map);
|
L.control.fullscreen().addTo(map);
|
||||||
@ -1527,6 +1542,26 @@ function doCommand(cmd) {
|
|||||||
layercontrol = L.control.layers(basemaps, overlays).addTo(map);
|
layercontrol = L.control.layers(basemaps, overlays).addTo(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cmd.hasOwnProperty("grid")) {
|
||||||
|
console.log("DING",cmd.grid);
|
||||||
|
if (cmd.grid.hasOwnProperty("showgrid")) {
|
||||||
|
var changed = false;
|
||||||
|
if ((cmd.grid.showgrid == "true" || cmd.grid.showgrid == true ) && !showGrid) { changed = true; }
|
||||||
|
if ((cmd.grid.showgrid == "false" || cmd.grid.showgrid == false ) && showGrid) { changed = true; }
|
||||||
|
if (changed) {
|
||||||
|
showGrid = !showGrid;
|
||||||
|
if (showGrid) { Lgrid.addTo(map); }
|
||||||
|
else { Lgrid.removeFrom(map); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cmd.grid.hasOwnProperty("opt")) {
|
||||||
|
Lgrid.initialize(cmd.grid.opt);
|
||||||
|
if (showGrid) {
|
||||||
|
Lgrid.removeFrom(map);
|
||||||
|
Lgrid.addTo(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (cmd.hasOwnProperty("button")) {
|
if (cmd.hasOwnProperty("button")) {
|
||||||
if (cmd.button.icon) {
|
if (cmd.button.icon) {
|
||||||
if (!buttons[cmd.button.name]) {
|
if (!buttons[cmd.button.name]) {
|
||||||
|
530
worldmap/leaflet/leaflet.latlng-graticule.js
Normal file
530
worldmap/leaflet/leaflet.latlng-graticule.js
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
/* eslint-disable indent,semi */
|
||||||
|
/**
|
||||||
|
* Create a Canvas as ImageOverlay to draw the Lat/Lon Graticule,
|
||||||
|
* and show the axis tick label on the edge of the map.
|
||||||
|
* Author: lanwei@cloudybay.com.tw
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (window, document, undefined) {
|
||||||
|
|
||||||
|
L.LatLngGraticule = L.Layer.extend({
|
||||||
|
includes: L.Mixin.Events,
|
||||||
|
|
||||||
|
options: {
|
||||||
|
showLabel: true,
|
||||||
|
opacity: 1,
|
||||||
|
weight: 0.8,
|
||||||
|
color: '#aaa',
|
||||||
|
font: '12px Verdana',
|
||||||
|
dashArray: [0,0],
|
||||||
|
lngLineCurved: 0,
|
||||||
|
latLineCurved: 0,
|
||||||
|
zoomInterval: [
|
||||||
|
{start: 2, end: 2, interval: 40},
|
||||||
|
{start: 3, end: 3, interval: 20},
|
||||||
|
{start: 4, end: 4, interval: 10},
|
||||||
|
{start: 5, end: 7, interval: 5},
|
||||||
|
{start: 8, end: 20, interval: 1}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (options) {
|
||||||
|
L.setOptions(this, options);
|
||||||
|
|
||||||
|
var defaultFontName = 'Verdana';
|
||||||
|
var _ff = this.options.font.split(' ');
|
||||||
|
if (_ff.length < 2) {
|
||||||
|
this.options.font += ' ' + defaultFontName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.options.fontColor) {
|
||||||
|
this.options.fontColor = this.options.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.zoomInterval) {
|
||||||
|
if (this.options.zoomInterval.latitude) {
|
||||||
|
this.options.latInterval = this.options.zoomInterval.latitude;
|
||||||
|
if (!this.options.zoomInterval.longitude) {
|
||||||
|
this.options.lngInterval = this.options.zoomInterval.latitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.options.zoomInterval.longitude) {
|
||||||
|
this.options.lngInterval = this.options.zoomInterval.longitude;
|
||||||
|
if (!this.options.zoomInterval.latitude) {
|
||||||
|
this.options.latInterval = this.options.zoomInterval.longitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.options.latInterval) {
|
||||||
|
this.options.latInterval = this.options.zoomInterval;
|
||||||
|
}
|
||||||
|
if (!this.options.lngInterval) {
|
||||||
|
this.options.lngInterval = this.options.zoomInterval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onAdd: function (map) {
|
||||||
|
this._map = map;
|
||||||
|
|
||||||
|
if (!this._canvas) {
|
||||||
|
this._initCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
|
map._panes.overlayPane.appendChild(this._canvas);
|
||||||
|
|
||||||
|
map.on('viewreset', this._reset, this);
|
||||||
|
map.on('move', this._reset, this);
|
||||||
|
map.on('moveend', this._reset, this);
|
||||||
|
|
||||||
|
if (map.options.zoomAnimation && L.Browser.any3d) {
|
||||||
|
map.on('zoomanim', this._animateZoom, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._reset();
|
||||||
|
},
|
||||||
|
|
||||||
|
onRemove: function (map) {
|
||||||
|
L.DomUtil.remove(this._canvas);
|
||||||
|
|
||||||
|
map.off('viewreset', this._reset, this);
|
||||||
|
map.off('move', this._reset, this);
|
||||||
|
map.off('moveend', this._reset, this);
|
||||||
|
|
||||||
|
if (map.options.zoomAnimation) {
|
||||||
|
map.off('zoomanim', this._animateZoom, this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addTo: function (map) {
|
||||||
|
map.addLayer(this);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
setOpacity: function (opacity) {
|
||||||
|
this.options.opacity = opacity;
|
||||||
|
this._updateOpacity();
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
bringToFront: function () {
|
||||||
|
if (this._canvas) {
|
||||||
|
//this._map._panes.overlayPane.appendChild(this._canvas);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
bringToBack: function () {
|
||||||
|
var pane = this._map._panes.overlayPane;
|
||||||
|
if (this._canvas) {
|
||||||
|
//pane.insertBefore(this._canvas, pane.firstChild);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAttribution: function () {
|
||||||
|
return this.options.attribution;
|
||||||
|
},
|
||||||
|
|
||||||
|
_initCanvas: function () {
|
||||||
|
|
||||||
|
this._canvas = L.DomUtil.create('canvas', '');
|
||||||
|
|
||||||
|
if (this._map.options.zoomAnimation && L.Browser.any3d) {
|
||||||
|
L.DomUtil.addClass(this._canvas, 'leaflet-zoom-animated');
|
||||||
|
} else {
|
||||||
|
L.DomUtil.addClass(this._canvas, 'leaflet-zoom-hide');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateOpacity();
|
||||||
|
|
||||||
|
|
||||||
|
L.extend(this._canvas, {
|
||||||
|
onselectstart: L.Util.falseFn,
|
||||||
|
onmousemove: L.Util.falseFn,
|
||||||
|
onload: L.bind(this._onCanvasLoad, this)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_animateZoom: function (e) {
|
||||||
|
var map = this._map,
|
||||||
|
canvas = this._canvas,
|
||||||
|
scale = map.getZoomScale(e.zoom),
|
||||||
|
nw = map.containerPointToLatLng([0, 0]),
|
||||||
|
se = map.containerPointToLatLng([canvas.width, canvas.height]),
|
||||||
|
topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center),
|
||||||
|
size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft),
|
||||||
|
origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale)));
|
||||||
|
|
||||||
|
L.DomUtil.setTransform(canvas, origin, scale);
|
||||||
|
},
|
||||||
|
|
||||||
|
_reset: function () {
|
||||||
|
var canvas = this._canvas,
|
||||||
|
size = this._map.getSize(),
|
||||||
|
lt = this._map.containerPointToLayerPoint([0, 0]);
|
||||||
|
|
||||||
|
L.DomUtil.setPosition(canvas, lt);
|
||||||
|
|
||||||
|
canvas.width = size.x;
|
||||||
|
canvas.height = size.y;
|
||||||
|
canvas.style.width = size.x + 'px';
|
||||||
|
canvas.style.height = size.y + 'px';
|
||||||
|
|
||||||
|
this.__calcInterval();
|
||||||
|
|
||||||
|
this.__draw(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCanvasLoad: function () {
|
||||||
|
this.fire('load');
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateOpacity: function () {
|
||||||
|
L.DomUtil.setOpacity(this._canvas, this.options.opacity);
|
||||||
|
},
|
||||||
|
|
||||||
|
__format_lat: function(lat) {
|
||||||
|
if (this.options.latFormatTickLabel) {
|
||||||
|
return this.options.latFormatTickLabel(lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: format type of float
|
||||||
|
if (lat < 0) {
|
||||||
|
return '' + (lat*-1) + 'S';
|
||||||
|
}
|
||||||
|
else if (lat > 0) {
|
||||||
|
return '' + lat + 'N';
|
||||||
|
}
|
||||||
|
return '' + lat;
|
||||||
|
},
|
||||||
|
|
||||||
|
__format_lng: function(lng) {
|
||||||
|
if (this.options.lngFormatTickLabel) {
|
||||||
|
return this.options.lngFormatTickLabel(lng);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: format type of float
|
||||||
|
if (lng > 180) {
|
||||||
|
return '' + (360 - lng) + 'W';
|
||||||
|
}
|
||||||
|
else if (lng > 0 && lng < 180) {
|
||||||
|
return '' + lng + 'E';
|
||||||
|
}
|
||||||
|
else if (lng < 0 && lng > -180) {
|
||||||
|
return '' + (lng*-1) + 'W';
|
||||||
|
}
|
||||||
|
else if (lng == -180) {
|
||||||
|
return '' + (lng*-1);
|
||||||
|
}
|
||||||
|
else if (lng < -180) {
|
||||||
|
return '' + (360 + lng) + 'W';
|
||||||
|
}
|
||||||
|
return '' + lng;
|
||||||
|
},
|
||||||
|
|
||||||
|
__calcInterval: function() {
|
||||||
|
var zoom = this._map.getZoom();
|
||||||
|
if (this._currZoom != zoom) {
|
||||||
|
this._currLngInterval = 0;
|
||||||
|
this._currLatInterval = 0;
|
||||||
|
this._currZoom = zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
var interv;
|
||||||
|
|
||||||
|
if (!this._currLngInterval) {
|
||||||
|
try {
|
||||||
|
for (var idx in this.options.lngInterval) {
|
||||||
|
var dict = this.options.lngInterval[idx];
|
||||||
|
if (dict.start <= zoom) {
|
||||||
|
if (dict.end && dict.end >= zoom) {
|
||||||
|
this._currLngInterval = dict.interval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
this._currLngInterval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._currLatInterval) {
|
||||||
|
try {
|
||||||
|
for (var idx in this.options.latInterval) {
|
||||||
|
var dict = this.options.latInterval[idx];
|
||||||
|
if (dict.start <= zoom) {
|
||||||
|
if (dict.end && dict.end >= zoom) {
|
||||||
|
this._currLatInterval = dict.interval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
this._currLatInterval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
__draw: function(label) {
|
||||||
|
function _parse_px_to_int(txt) {
|
||||||
|
if (txt.length > 2) {
|
||||||
|
if (txt.charAt(txt.length-2) == 'p') {
|
||||||
|
txt = txt.substr(0, txt.length-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return parseInt(txt, 10);
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = this,
|
||||||
|
canvas = this._canvas,
|
||||||
|
map = this._map,
|
||||||
|
curvedLon = this.options.lngLineCurved,
|
||||||
|
curvedLat = this.options.latLineCurved;
|
||||||
|
|
||||||
|
if (L.Browser.canvas && map) {
|
||||||
|
if (!this._currLngInterval || !this._currLatInterval) {
|
||||||
|
this.__calcInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
var latInterval = this._currLatInterval,
|
||||||
|
lngInterval = this._currLngInterval;
|
||||||
|
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.lineWidth = this.options.weight;
|
||||||
|
ctx.strokeStyle = this.options.color;
|
||||||
|
ctx.fillStyle = this.options.fontColor;
|
||||||
|
ctx.setLineDash(this.options.dashArray);
|
||||||
|
|
||||||
|
if (this.options.font) {
|
||||||
|
ctx.font = this.options.font;
|
||||||
|
}
|
||||||
|
var txtWidth = ctx.measureText('0').width;
|
||||||
|
var txtHeight = 12;
|
||||||
|
try {
|
||||||
|
var _font_size = ctx.font.split(' ')[0];
|
||||||
|
txtHeight = _parse_px_to_int(_font_size);
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
|
|
||||||
|
var ww = canvas.width,
|
||||||
|
hh = canvas.height;
|
||||||
|
|
||||||
|
var lt = map.containerPointToLatLng(L.point(0, 0));
|
||||||
|
var rt = map.containerPointToLatLng(L.point(ww, 0));
|
||||||
|
var rb = map.containerPointToLatLng(L.point(ww, hh));
|
||||||
|
|
||||||
|
var _lat_b = rb.lat,
|
||||||
|
_lat_t = lt.lat;
|
||||||
|
var _lon_l = lt.lng,
|
||||||
|
_lon_r = rt.lng;
|
||||||
|
|
||||||
|
var _point_per_lat = (_lat_t - _lat_b) / (hh * 0.2);
|
||||||
|
if (isNaN(_point_per_lat)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_point_per_lat < 1) { _point_per_lat = 1; }
|
||||||
|
if (_lat_b < -90) {
|
||||||
|
_lat_b = -90;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lat_b = parseInt(_lat_b - _point_per_lat, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lat_t > 90) {
|
||||||
|
_lat_t = 90;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lat_t = parseInt(_lat_t + _point_per_lat, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
var _point_per_lon = (_lon_r - _lon_l) / (ww * 0.2);
|
||||||
|
if (_point_per_lon < 1) { _point_per_lon = 1; }
|
||||||
|
if (_lon_l > 0 && _lon_r < 0) {
|
||||||
|
_lon_r += 360;
|
||||||
|
}
|
||||||
|
_lon_r = parseInt(_lon_r + _point_per_lon, 10);
|
||||||
|
_lon_l = parseInt(_lon_l - _point_per_lon, 10);
|
||||||
|
|
||||||
|
var ll, latstr, lngstr, _lon_delta = 0.5;
|
||||||
|
function __draw_lat_line(self, lat_tick) {
|
||||||
|
ll = self._latLngToCanvasPoint(L.latLng(lat_tick, _lon_l));
|
||||||
|
latstr = self.__format_lat(lat_tick);
|
||||||
|
txtWidth = ctx.measureText(latstr).width;
|
||||||
|
|
||||||
|
if (curvedLat) {
|
||||||
|
if (typeof(curvedLat) == 'number') {
|
||||||
|
_lon_delta = curvedLat;
|
||||||
|
}
|
||||||
|
|
||||||
|
var __lon_left = _lon_l, __lon_right = _lon_r;
|
||||||
|
if (ll.x > 0) {
|
||||||
|
var __lon_left = map.containerPointToLatLng(L.point(0, ll.y));
|
||||||
|
__lon_left = __lon_left.lng - _point_per_lon;
|
||||||
|
ll.x = 0;
|
||||||
|
}
|
||||||
|
var rr = self._latLngToCanvasPoint(L.latLng(lat_tick, __lon_right));
|
||||||
|
if (rr.x < ww) {
|
||||||
|
__lon_right = map.containerPointToLatLng(L.point(ww, rr.y));
|
||||||
|
__lon_right = __lon_right.lng + _point_per_lon;
|
||||||
|
if (__lon_left > 0 && __lon_right < 0) {
|
||||||
|
__lon_right += 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(ll.x, ll.y);
|
||||||
|
var _prev_p = null;
|
||||||
|
for (var j=__lon_left; j<=__lon_right; j+=_lon_delta) {
|
||||||
|
rr = self._latLngToCanvasPoint(L.latLng(lat_tick, j));
|
||||||
|
ctx.lineTo(rr.x, rr.y);
|
||||||
|
|
||||||
|
if (self.options.showLabel && label && _prev_p != null) {
|
||||||
|
if (_prev_p.x < 0 && rr.x >= 0) {
|
||||||
|
var _s = (rr.x - 0) / (rr.x - _prev_p.x);
|
||||||
|
var _y = rr.y - ((rr.y - _prev_p.y) * _s);
|
||||||
|
ctx.fillText(latstr, 0, _y + (txtHeight/2));
|
||||||
|
}
|
||||||
|
else if (_prev_p.x <= (ww-txtWidth) && rr.x > (ww-txtWidth)) {
|
||||||
|
var _s = (rr.x - ww) / (rr.x - _prev_p.x);
|
||||||
|
var _y = rr.y - ((rr.y - _prev_p.y) * _s);
|
||||||
|
ctx.fillText(latstr, ww-txtWidth, _y + (txtHeight/2)-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_prev_p = {x:rr.x, y:rr.y, lon:j, lat:i};
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var __lon_right = _lon_r;
|
||||||
|
var rr = self._latLngToCanvasPoint(L.latLng(lat_tick, __lon_right));
|
||||||
|
if (curvedLon) {
|
||||||
|
__lon_right = map.containerPointToLatLng(L.point(0, rr.y));
|
||||||
|
__lon_right = __lon_right.lng;
|
||||||
|
rr = self._latLngToCanvasPoint(L.latLng(lat_tick, __lon_right));
|
||||||
|
|
||||||
|
var __lon_left = map.containerPointToLatLng(L.point(ww, rr.y));
|
||||||
|
__lon_left = __lon_left.lng;
|
||||||
|
ll = self._latLngToCanvasPoint(L.latLng(lat_tick, __lon_left));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(ll.x+1, ll.y);
|
||||||
|
ctx.lineTo(rr.x-1, rr.y);
|
||||||
|
ctx.stroke();
|
||||||
|
if (self.options.showLabel && label) {
|
||||||
|
var _yy = ll.y + (txtHeight/2)-2;
|
||||||
|
ctx.fillText(latstr, 0, _yy);
|
||||||
|
ctx.fillText(latstr, ww-txtWidth, _yy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (latInterval > 0) {
|
||||||
|
for (var i=latInterval; i<=_lat_t; i+=latInterval) {
|
||||||
|
if (i >= _lat_b) {
|
||||||
|
__draw_lat_line(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i=0; i>=_lat_b; i-=latInterval) {
|
||||||
|
if (i <= _lat_t) {
|
||||||
|
__draw_lat_line(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __draw_lon_line(self, lon_tick) {
|
||||||
|
lngstr = self.__format_lng(lon_tick);
|
||||||
|
txtWidth = ctx.measureText(lngstr).width;
|
||||||
|
var bb = self._latLngToCanvasPoint(L.latLng(_lat_b, lon_tick));
|
||||||
|
|
||||||
|
if (curvedLon) {
|
||||||
|
if (typeof(curvedLon) == 'number') {
|
||||||
|
_lat_delta = curvedLon;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(bb.x, bb.y);
|
||||||
|
var _prev_p = null;
|
||||||
|
for (var j=_lat_b; j<_lat_t; j+=_lat_delta) {
|
||||||
|
var tt = self._latLngToCanvasPoint(L.latLng(j, lon_tick));
|
||||||
|
ctx.lineTo(tt.x, tt.y);
|
||||||
|
|
||||||
|
if (self.options.showLabel && label && _prev_p != null) {
|
||||||
|
if (_prev_p.y > 8 && tt.y <= 8) {
|
||||||
|
ctx.fillText(lngstr, tt.x - (txtWidth/2), txtHeight);
|
||||||
|
}
|
||||||
|
else if (_prev_p.y >= hh && tt.y < hh) {
|
||||||
|
ctx.fillText(lngstr, tt.x - (txtWidth/2), hh-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_prev_p = {x:tt.x, y:tt.y, lon:lon_tick, lat:j};
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var __lat_top = _lat_t;
|
||||||
|
var tt = self._latLngToCanvasPoint(L.latLng(__lat_top, lon_tick));
|
||||||
|
if (curvedLat) {
|
||||||
|
__lat_top = map.containerPointToLatLng(L.point(tt.x, 0));
|
||||||
|
__lat_top = __lat_top.lat;
|
||||||
|
if (__lat_top > 90) { __lat_top = 90; }
|
||||||
|
tt = self._latLngToCanvasPoint(L.latLng(__lat_top, lon_tick));
|
||||||
|
|
||||||
|
var __lat_bottom = map.containerPointToLatLng(L.point(bb.x, hh));
|
||||||
|
__lat_bottom = __lat_bottom.lat;
|
||||||
|
if (__lat_bottom < -90) { __lat_bottom = -90; }
|
||||||
|
bb = self._latLngToCanvasPoint(L.latLng(__lat_bottom, lon_tick));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(tt.x, tt.y+1);
|
||||||
|
ctx.lineTo(bb.x, bb.y-1);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
if (self.options.showLabel && label) {
|
||||||
|
ctx.fillText(lngstr, tt.x - (txtWidth/2), txtHeight+1);
|
||||||
|
ctx.fillText(lngstr, bb.x - (txtWidth/2), hh-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lngInterval > 0) {
|
||||||
|
for (var i=lngInterval; i<=_lon_r; i+=lngInterval) {
|
||||||
|
if (i >= _lon_l) {
|
||||||
|
__draw_lon_line(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i=0; i>=_lon_l; i-=lngInterval) {
|
||||||
|
if (i <= _lon_r) {
|
||||||
|
__draw_lon_line(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_latLngToCanvasPoint: function(latlng) {
|
||||||
|
var map = this._map;
|
||||||
|
var projectedPoint = map.project(L.latLng(latlng));
|
||||||
|
projectedPoint._subtract(map.getPixelOrigin());
|
||||||
|
return L.point(projectedPoint).add(map._getMapPanePos());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
L.latlngGraticule = function (options) {
|
||||||
|
return new L.LatLngGraticule(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}(this, document));
|
Loading…
Reference in New Issue
Block a user