mapv
Version:
a library of geography visualization
335 lines (304 loc) • 8.04 kB
JavaScript
/**
* MapV for openlayers (https://openlayers.org)
* @author sakitam-fdd - https://github.com/sakitam-fdd
*/
import BaseLayer from "../BaseLayer";
import clear from "../../canvas/clear";
import DataSet from "../../data/DataSet";
import TWEEN from "../../utils/Tween";
/**
* create canvas
* @param width
* @param height
* @returns {HTMLCanvasElement}
*/
const createCanvas = (width, height) => {
if (typeof document !== 'undefined') {
const canvas = document.createElement('canvas')
canvas.width = width;
canvas.height = height;
return canvas;
} else {
// create a new canvas instance in node.js
// the canvas class needs to have a default constructor without any parameter
}
}
class Layer extends BaseLayer {
constructor (map = null, dataSet, options) {
super(map, dataSet, options);
this.options = options;
/**
* internal
* @type {{canvas: null, devicePixelRatio: number}}
*/
this.canvasLayer = {
canvas: null,
devicePixelRatio: window.devicePixelRatio
}
/**
* cavnas layer
* @type {null}
* @private
*/
this.layer_ = null;
/**
* previous cursor
* @type {undefined}
* @private
*/
this.previousCursor_ = undefined
this.init(map, options);
this.argCheck(options);
}
/**
* init mapv layer
* @param map
* @param options
*/
init (map, options) {
if (map && map instanceof ol.Map) {
this.$Map = map;
this.context = this.options.context || '2d';
this.getCanvasLayer();
this.initDataRange(options);
this.initAnimator();
this.onEvents()
} else {
throw new Error('not map object')
}
}
/**
* update layer
* @param time
* @private
*/
_canvasUpdate (time) {
this.render(this.canvasLayer.canvas, time);
}
/**
* render layer
* @param canvas
* @param time
* @returns {Layer}
*/
render (canvas, time) {
const map = this.$Map;
const context = canvas.getContext(this.context);
const animationOptions = this.options.animation;
const _projection = this.options.hasOwnProperty('projection') ? this.options.projection : 'EPSG:4326';
if (this.isEnabledTime()) {
if (time === undefined) {
clear(context);
return this;
}
if (this.context === '2d') {
context.save();
context.globalCompositeOperation = 'destination-out';
context.fillStyle = 'rgba(0, 0, 0, .1)';
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
context.restore();
}
} else {
clear(context);
}
if (this.context === '2d') {
for (const key in this.options) {
context[key] = this.options[key];
}
} else {
context.clear(context.COLOR_BUFFER_BIT);
}
const dataGetOptions = {
transferCoordinate: function(coordinate) {
return map.getPixelFromCoordinate(ol.proj.transform(coordinate, _projection, 'EPSG:4326'));
}
};
if (time !== undefined) {
dataGetOptions.filter = function(item) {
const trails = animationOptions.trails || 10;
if (time && item.time > (time - trails) && item.time < time) {
return true;
} else {
return false;
}
}
}
const data = this.dataSet.get(dataGetOptions);
this.processData(data);
if (this.options.unit === 'm') {
if (this.options.size) {
this.options._size = this.options.size / zoomUnit;
}
if (this.options.width) {
this.options._width = this.options.width / zoomUnit;
}
if (this.options.height) {
this.options._height = this.options.height / zoomUnit;
}
} else {
this.options._size = this.options.size;
this.options._height = this.options.height;
this.options._width = this.options.width;
}
this.drawContext(context, new DataSet(data), this.options, {x: 0, y: 0});
this.options.updateCallback && this.options.updateCallback(time);
return this
}
/**
* get canvas layer
*/
getCanvasLayer () {
if (!this.canvasLayer.canvas && !this.layer_) {
const extent = this.getMapExtent();
this.layer_ = new ol.layer.Image({
layerName: this.options.layerName,
minResolution: this.options.minResolution,
maxResolution: this.options.maxResolution,
zIndex: this.options.zIndex,
extent: extent,
source: new ol.source.ImageCanvas({
canvasFunction: this.canvasFunction.bind(this),
projection: (this.options.hasOwnProperty('projection') ? this.options.projection : 'EPSG:4326'),
ratio: (this.options.hasOwnProperty('ratio') ? this.options.ratio : 1)
})
});
this.$Map.addLayer(this.layer_);
this.$Map.un('precompose', this.reRender, this);
this.$Map.on('precompose', this.reRender, this);
}
}
/**
* re render
*/
reRender () {
if (!this.layer_) return;
const extent = this.getMapExtent();
this.layer_.setExtent(extent);
}
/**
* canvas constructor
* @param extent
* @param resolution
* @param pixelRatio
* @param size
* @param projection
* @returns {*}
*/
canvasFunction (extent, resolution, pixelRatio, size, projection) {
if (!this.canvasLayer.canvas) {
this.canvasLayer.canvas = createCanvas(size[0], size[1])
} else {
this.canvasLayer.canvas.width = size[0];
this.canvasLayer.canvas.height = size[1];
}
this.render(this.canvasLayer.canvas)
return this.canvasLayer.canvas
}
/**
* get map current extent
* @returns {Array}
*/
getMapExtent () {
const size = this.$Map.getSize();
return this.$Map.getView().calculateExtent(size);
}
/**
* add layer to map
* @param map
*/
addTo (map) {
this.init(map, this.options);
}
/**
* remove layer
*/
removeLayer () {
if (!this.$Map) return;
this.unEvents();
this.$Map.un('precompose', this.reRender, this);
this.$Map.removeLayer(this.layer_);
delete this.$Map;
delete this.layer_;
delete this.canvasLayer.canvas;
}
getContext() {
return this.canvasLayer.canvas.getContext(this.context);
}
/**
* handle click event
* @param event
*/
clickEvent(event) {
const pixel = event.pixel;
super.clickEvent({
x: pixel[0],
y: pixel[1]
}, event);
}
/**
* handle mousemove/pointermove event
* @param event
*/
mousemoveEvent(event) {
const pixel = event.pixel;
super.mousemoveEvent({
x: pixel[0],
y: pixel[1]
}, event);
}
/**
* add animator event
*/
addAnimatorEvent() {
this.$Map.on('movestart', this.animatorMovestartEvent, this);
this.$Map.on('moveend', this.animatorMoveendEvent, this);
}
/**
* bind event
*/
onEvents () {
const map = this.$Map;
this.unEvents();
if (this.options.methods) {
if (this.options.methods.click) {
map.on('click', this.clickEvent, this);
}
if (this.options.methods.mousemove) {
map.on('pointermove', this.mousemoveEvent, this);
}
}
}
/**
* unbind events
*/
unEvents () {
const map = this.$Map;
if (this.options.methods) {
if (this.options.methods.click) {
map.un('click', this.clickEvent, this);
}
if (this.options.methods.pointermove) {
map.un('pointermove', this.mousemoveEvent, this);
}
}
}
/**
* set map cursor
* @param cursor
* @param feature
*/
setDefaultCursor (cursor, feature) {
if (!this.$Map) return;
const element = this.$Map.getTargetElement()
if (feature) {
if (element.style.cursor !== cursor) {
this.previousCursor_ = element.style.cursor
element.style.cursor = cursor
}
} else if (this.previousCursor_ !== undefined) {
element.style.cursor = this.previousCursor_
this.previousCursor_ = undefined
}
}
}
export default Layer