293 lines
8.4 KiB
JavaScript
293 lines
8.4 KiB
JavaScript
|
(function (global, factory) {
|
|||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|||
|
typeof define === 'function' && define.amd ? define(factory) :
|
|||
|
(global.PointLine = factory());
|
|||
|
}(this, (function () { 'use strict';
|
|||
|
|
|||
|
/**
|
|||
|
* @author https://github.com/chengquan223
|
|||
|
* @Date 2017-02-27
|
|||
|
* */
|
|||
|
function CanvasLayer(options) {
|
|||
|
this.options = options || {};
|
|||
|
this.paneName = this.options.paneName || 'labelPane';
|
|||
|
this.zIndex = this.options.zIndex || 0;
|
|||
|
this._map = options.map;
|
|||
|
this._lastDrawTime = null;
|
|||
|
this.show();
|
|||
|
}
|
|||
|
|
|||
|
CanvasLayer.prototype = new BMap.Overlay();
|
|||
|
|
|||
|
CanvasLayer.prototype.initialize = function (map) {
|
|||
|
this._map = map;
|
|||
|
var canvas = this.canvas = document.createElement('canvas');
|
|||
|
var ctx = this.ctx = this.canvas.getContext('2d');
|
|||
|
canvas.style.cssText = 'position:absolute;' + 'left:0;' + 'top:0;' + 'z-index:' + this.zIndex + ';';
|
|||
|
this.adjustSize();
|
|||
|
this.adjustRatio(ctx);
|
|||
|
map.getPanes()[this.paneName].appendChild(canvas);
|
|||
|
var that = this;
|
|||
|
map.addEventListener('resize', function () {
|
|||
|
that.adjustSize();
|
|||
|
that._draw();
|
|||
|
});
|
|||
|
return this.canvas;
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.adjustSize = function () {
|
|||
|
var size = this._map.getSize();
|
|||
|
var canvas = this.canvas;
|
|||
|
canvas.width = size.width;
|
|||
|
canvas.height = size.height;
|
|||
|
canvas.style.width = canvas.width + 'px';
|
|||
|
canvas.style.height = canvas.height + 'px';
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.adjustRatio = function (ctx) {
|
|||
|
var backingStore = ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
|
|||
|
var pixelRatio = (window.devicePixelRatio || 1) / backingStore;
|
|||
|
var canvasWidth = ctx.canvas.width;
|
|||
|
var canvasHeight = ctx.canvas.height;
|
|||
|
ctx.canvas.width = canvasWidth * pixelRatio;
|
|||
|
ctx.canvas.height = canvasHeight * pixelRatio;
|
|||
|
ctx.canvas.style.width = canvasWidth + 'px';
|
|||
|
ctx.canvas.style.height = canvasHeight + 'px';
|
|||
|
// console.log(ctx.canvas.height, canvasHeight);
|
|||
|
ctx.scale(pixelRatio, pixelRatio);
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.draw = function () {
|
|||
|
var self = this;
|
|||
|
var args = arguments;
|
|||
|
|
|||
|
clearTimeout(self.timeoutID);
|
|||
|
self.timeoutID = setTimeout(function () {
|
|||
|
self._draw();
|
|||
|
}, 15);
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype._draw = function () {
|
|||
|
var map = this._map;
|
|||
|
var size = map.getSize();
|
|||
|
var center = map.getCenter();
|
|||
|
if (center) {
|
|||
|
var pixel = map.pointToOverlayPixel(center);
|
|||
|
this.canvas.style.left = pixel.x - size.width / 2 + 'px';
|
|||
|
this.canvas.style.top = pixel.y - size.height / 2 + 'px';
|
|||
|
this.dispatchEvent('draw');
|
|||
|
this.options.update && this.options.update.call(this);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.getContainer = function () {
|
|||
|
return this.canvas;
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.show = function () {
|
|||
|
if (!this.canvas) {
|
|||
|
this._map.addOverlay(this);
|
|||
|
}
|
|||
|
this.canvas.style.display = 'block';
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.hide = function () {
|
|||
|
this.canvas.style.display = 'none';
|
|||
|
//this._map.removeOverlay(this);
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.setZIndex = function (zIndex) {
|
|||
|
this.canvas.style.zIndex = zIndex;
|
|||
|
};
|
|||
|
|
|||
|
CanvasLayer.prototype.getZIndex = function () {
|
|||
|
return this.zIndex;
|
|||
|
};
|
|||
|
|
|||
|
var tool = {
|
|||
|
merge: function merge(settings, defaults) {
|
|||
|
Object.keys(settings).forEach(function (key) {
|
|||
|
defaults[key] = settings[key];
|
|||
|
});
|
|||
|
},
|
|||
|
//计算两点间距离
|
|||
|
getDistance: function getDistance(p1, p2) {
|
|||
|
return Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));
|
|||
|
},
|
|||
|
//判断点是否在线段上
|
|||
|
containStroke: function containStroke(x0, y0, x1, y1, lineWidth, x, y) {
|
|||
|
if (lineWidth === 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
var _l = lineWidth;
|
|||
|
var _a = 0;
|
|||
|
var _b = x0;
|
|||
|
// Quick reject
|
|||
|
if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (x0 !== x1) {
|
|||
|
_a = (y0 - y1) / (x0 - x1);
|
|||
|
_b = (x0 * y1 - x1 * y0) / (x0 - x1);
|
|||
|
} else {
|
|||
|
return Math.abs(x - x0) <= _l / 2;
|
|||
|
}
|
|||
|
var tmp = _a * x - y + _b;
|
|||
|
var _s = tmp * tmp / (_a * _a + 1);
|
|||
|
return _s <= _l / 2 * _l / 2;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var PointLine = function PointLine(map, userOptions) {
|
|||
|
var self = this;
|
|||
|
|
|||
|
self.map = map;
|
|||
|
self.lines = [];
|
|||
|
self.pixelList = [];
|
|||
|
|
|||
|
//默认参数
|
|||
|
var options = {
|
|||
|
//线条宽度
|
|||
|
lineWidth: 1,
|
|||
|
//线条颜色
|
|||
|
lineStyle: '#F9815C'
|
|||
|
};
|
|||
|
|
|||
|
//全局变量
|
|||
|
var baseLayer = null,
|
|||
|
width = map.getSize().width,
|
|||
|
height = map.getSize().height;
|
|||
|
|
|||
|
function Line(opts) {
|
|||
|
this.name = opts.name;
|
|||
|
this.path = opts.path;
|
|||
|
}
|
|||
|
|
|||
|
Line.prototype.getPointList = function () {
|
|||
|
var points = [],
|
|||
|
path = this.path;
|
|||
|
if (path && path.length > 0) {
|
|||
|
path.forEach(function (p) {
|
|||
|
points.push({
|
|||
|
name: p.name,
|
|||
|
pixel: map.pointToPixel(p.location)
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
return points;
|
|||
|
};
|
|||
|
|
|||
|
Line.prototype.draw = function (context) {
|
|||
|
var pointList = this.pixelList || this.getPointList();
|
|||
|
context.save();
|
|||
|
context.beginPath();
|
|||
|
context.lineWidth = options.lineWidth;
|
|||
|
context.strokeStyle = options.lineStyle;
|
|||
|
context.moveTo(pointList[0].pixel.x, pointList[0].pixel.y);
|
|||
|
for (var i = 0, len = pointList.length; i < len; i++) {
|
|||
|
context.lineTo(pointList[i].pixel.x, pointList[i].pixel.y);
|
|||
|
}
|
|||
|
context.stroke();
|
|||
|
context.closePath();
|
|||
|
context.restore();
|
|||
|
};
|
|||
|
|
|||
|
//底层canvas渲染,标注,线条
|
|||
|
var brush = function brush() {
|
|||
|
var baseCtx = baseLayer.canvas.getContext('2d');
|
|||
|
if (!baseCtx) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
addLine();
|
|||
|
|
|||
|
baseCtx.clearRect(0, 0, width, height);
|
|||
|
|
|||
|
self.pixelList = [];
|
|||
|
self.lines.forEach(function (line) {
|
|||
|
self.pixelList.push({
|
|||
|
name: line.name,
|
|||
|
data: line.getPointList()
|
|||
|
});
|
|||
|
line.draw(baseCtx);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
var addLine = function addLine() {
|
|||
|
if (self.lines && self.lines.length > 0) return;
|
|||
|
var dataset = options.data;
|
|||
|
dataset.forEach(function (l, i) {
|
|||
|
var line = new Line({
|
|||
|
name: l.name,
|
|||
|
path: []
|
|||
|
});
|
|||
|
l.data.forEach(function (p, j) {
|
|||
|
line.path.push({
|
|||
|
name: p.name,
|
|||
|
location: new BMap.Point(p.Longitude, p.Latitude)
|
|||
|
});
|
|||
|
});
|
|||
|
self.lines.push(line);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
self.init(userOptions, options);
|
|||
|
|
|||
|
baseLayer = new CanvasLayer({
|
|||
|
map: map,
|
|||
|
update: brush
|
|||
|
});
|
|||
|
|
|||
|
this.clickEvent = this.clickEvent.bind(this);
|
|||
|
|
|||
|
this.bindEvent();
|
|||
|
};
|
|||
|
|
|||
|
PointLine.prototype.init = function (settings, defaults) {
|
|||
|
//合并参数
|
|||
|
tool.merge(settings, defaults);
|
|||
|
|
|||
|
this.options = defaults;
|
|||
|
};
|
|||
|
|
|||
|
PointLine.prototype.bindEvent = function (e) {
|
|||
|
var map = this.map;
|
|||
|
if (this.options.methods) {
|
|||
|
if (this.options.methods.click) {
|
|||
|
map.setDefaultCursor("default");
|
|||
|
map.addEventListener('click', this.clickEvent);
|
|||
|
}
|
|||
|
if (this.options.methods.mousemove) {
|
|||
|
map.setDefaultCursor("default");
|
|||
|
map.addEventListener('mousemove', this.clickEvent);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
PointLine.prototype.clickEvent = function (e) {
|
|||
|
var self = this,
|
|||
|
lines = self.pixelList;
|
|||
|
if (lines.length > 0) {
|
|||
|
lines.forEach(function (line, i) {
|
|||
|
for (var j = 0; j < line.data.length; j++) {
|
|||
|
var beginPt = line.data[j].pixel;
|
|||
|
if (line.data[j + 1] == undefined) {
|
|||
|
return;
|
|||
|
}
|
|||
|
var endPt = line.data[j + 1].pixel;
|
|||
|
var curPt = e.pixel;
|
|||
|
var isOnLine = tool.containStroke(beginPt.x, beginPt.y, endPt.x, endPt.y, self.options.lineWidth, curPt.x, curPt.y);
|
|||
|
if (isOnLine) {
|
|||
|
self.options.methods.click(e, line.name);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
return PointLine;
|
|||
|
|
|||
|
})));
|