ol-ext
Version:
A set of cool extensions for OpenLayers (ol) in node modules structure
272 lines (246 loc) • 8.56 kB
JavaScript
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol_control_CanvasBase from './CanvasBase.js'
import ol_style_Style from 'ol/style/Style.js'
import ol_style_Stroke from 'ol/style/Stroke.js'
import ol_ext_element from '../util/element.js';
/**
* Draw a compass on the map. The position/size of the control is defined in the css.
*
* @constructor
* @extends {ol_control_CanvasBase}
* @param {Object=} options Control options. The style {_ol_style_Stroke_} option is usesd to draw the text.
* @param {string} options.className class name for the control
* @param {boolean} [options.visible=true]
* @param {Image} options.image an image, default use the src option or a default image
* @param {string} options.src image src or 'default' or 'compact', default use the image option or a default image
* @param {boolean} options.rotateVithView rotate vith view (false to show watermark), default true
* @param {ol_style_Stroke} options.style style to draw the lines, default draw no lines
*/
var ol_control_Compass = class olcontrolCompass extends ol_control_CanvasBase {
constructor(options) {
options = options || {};
// Initialize parent
var elt = document.createElement("div");
elt.className = "ol-control ol-compassctrl ol-unselectable ol-hidden" + (options.className ? " " + options.className : "");
elt.style.position = "absolute";
elt.style.visibility = "hidden";
var style = (options.style instanceof ol_style_Stroke) ? new ol_style_Style({ stroke: options.style }) : options.style;
if (!options.style) {
style = new ol_style_Style({ stroke: new ol_style_Stroke({ width: 0 }) });
}
super({
element: elt,
style: style
});
this.set('rotateVithView', options.rotateWithView !== false);
this.setVisible(options.visible !== false);
this.setImage(options.image || options.src);
}
/** Set compass image
* @param {Image|string} [img=default] the image or an url or 'compact' or 'default'
*/
setImage(img) {
// The image
if (img instanceof Image) {
this.img_ = img;
this.img_.onload = function () {
if (this.getMap()) {
try { this.getMap().renderSync(); } catch (e) { /* ok */ }
}
}.bind(this);
} else if (typeof (img) === 'string') {
// Load source
switch (img) {
case 'compact': {
this.img_ = this.compactCompass_(this.element.clientWidth, this.getStroke().getColor());
break;
}
case 'default': {
this.img_ = this.defaultCompass_(this.element.clientWidth, this.getStroke().getColor());
break;
}
default: {
this.img_ = new Image();
this.img_.onload = function () {
if (this.getMap()) {
try { this.getMap().renderSync(); } catch (e) { /* ok */ }
}
}.bind(this);
this.img_.src = img;
break;
}
}
} else {
this.img_ = this.defaultCompass_(this.element.clientWidth, this.getStroke().getColor());
}
}
/** Create a default image.
* @param {number} s the size of the compass
* @private
*/
compactCompass_(s, color) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
s = canvas.width = canvas.height = s || 150;
var r = s / 2;
ctx.translate(r, r);
ctx.fillStyle = color || '#963';
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.font = 'bold ' + (r * 0.4) + 'px sans-serif';
ctx.textBaseline = 'bottom';
ctx.textAlign = 'center';
ctx.strokeStyle = '#fff';
ctx.globalAlpha = .75;
ctx.strokeText('N', 0, -r / 2);
ctx.globalAlpha = 1;
ctx.fillText('N', 0, -r / 2);
ctx.beginPath();
ctx.moveTo(0, r / 4);
ctx.lineTo(r / 3, r / 2);
ctx.lineTo(0, -r / 2);
ctx.lineTo(-r / 3, r / 2);
ctx.lineTo(0, r / 4);
ctx.lineWidth = 12;
ctx.fillStyle = "#fff";
ctx.globalAlpha = .75;
ctx.fill();
ctx.stroke();
ctx.globalAlpha = 1;
ctx.fillStyle = ctx.strokeStyle = color || '#963';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(0, r / 4);
ctx.lineTo(0, -r / 2);
ctx.lineTo(r / 3, r / 2);
ctx.lineTo(0, r / 4);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, r / 4);
ctx.lineTo(0, -r / 2);
ctx.lineTo(-r / 3, r / 2);
ctx.lineTo(0, r / 4);
ctx.stroke();
return canvas;
}
/** Create a default image.
* @param {number} s the size of the compass
* @private
*/
defaultCompass_(s, color) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
s = canvas.width = canvas.height = s || 150;
var r = s / 2;
var r2 = 0.22 * r;
function draw(r, r2) {
ctx.fillStyle = color || "#963";
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(r, 0); ctx.lineTo(r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(-r, 0); ctx.lineTo(-r2, -r2); ctx.moveTo(0, 0);
ctx.lineTo(0, r); ctx.lineTo(-r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(0, -r); ctx.lineTo(r2, -r2); ctx.moveTo(0, 0);
ctx.fill();
ctx.stroke();
}
function draw2(r, r2) {
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "#fff";
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(r, 0); ctx.lineTo(r2, -r2); ctx.moveTo(0, 0);
ctx.lineTo(-r, 0); ctx.lineTo(-r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(0, r); ctx.lineTo(r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(0, -r); ctx.lineTo(-r2, -r2); ctx.moveTo(0, 0);
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(r, 0); ctx.lineTo(r2, -r2); ctx.moveTo(0, 0);
ctx.lineTo(-r, 0); ctx.lineTo(-r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(0, r); ctx.lineTo(r2, r2); ctx.moveTo(0, 0);
ctx.lineTo(0, -r); ctx.lineTo(-r2, -r2); ctx.moveTo(0, 0);
ctx.stroke();
}
ctx.translate(r, r);
ctx.strokeStyle = color || "#963";
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.arc(0, 0, s * 0.41, 0, 2 * Math.PI);
ctx.arc(0, 0, s * 0.44, 0, 2 * Math.PI);
ctx.stroke();
ctx.rotate(Math.PI / 4);
draw(r * 0.9, r2 * 0.8);
draw2(r * 0.9, r2 * 0.8);
ctx.rotate(-Math.PI / 4);
draw(r, r2);
draw2(r, r2);
return canvas;
}
/** Get control visibility
* @return {boolean}
*/
getVisible() {
return ol_ext_element.getStyle(this.element, 'display') === 'block';
}
/** Set visibility
* @param {boolean} b
*/
setVisible(b) {
if (b)
this.element.classList.add('ol-visible');
else
this.element.classList.remove('ol-visible');
if (this.getMap())
this.getMap().render();
}
/** Draw compass
* @param {ol.event} e postcompose event
* @private
*/
_draw(e) {
var ctx = this.getContext(e);
if (!ctx || !this.getVisible())
return;
var canvas = ctx.canvas;
// 8 angles
var i, da = [];
for (i = 0; i < 8; i++)
da[i] = [Math.cos(Math.PI * i / 8), Math.sin(Math.PI * i / 8)];
// Retina device
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio, ratio);
var w = this.element.clientWidth;
var h = this.element.clientHeight;
var pos = { left: this.element.offsetLeft, top: this.element.offsetTop };
var compass = this.img_;
var rot = e.frameState.viewState.rotation;
ctx.beginPath();
ctx.translate(pos.left + w / 2, pos.top + h / 2);
if (this.get('rotateVithView'))
ctx.rotate(rot);
if (this.getStroke().getWidth()) {
ctx.beginPath();
ctx.strokeStyle = this.getStroke().getColor();
ctx.lineWidth = this.getStroke().getWidth();
var m = Math.max(canvas.width, canvas.height);
for (i = 0; i < 8; i++) {
ctx.moveTo(-da[i][0] * m, -da[i][1] * m);
ctx.lineTo(da[i][0] * m, da[i][1] * m);
}
ctx.stroke();
}
if (compass.width) {
ctx.drawImage(compass, -w / 2, -h / 2, w, h);
}
ctx.closePath();
ctx.restore();
}
}
export default ol_control_Compass