cesium-examples/map/2d/build/google-map-flashMarker.js

395 lines
12 KiB
JavaScript
Raw Permalink Normal View History

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.FlashMarker = factory());
}(this, (function () { 'use strict';
function CanvasLayer(opt_options) {
this.isAdded_ = false;
this.isAnimated_ = false;
this.paneName_ = CanvasLayer.DEFAULT_PANE_NAME_;
this.updateHandler_ = null;
this.resizeHandler_ = null;
this.topLeft_ = null;
this.centerListener_ = null;
this.resizeListener_ = null;
this.needsResize_ = true;
this.requestAnimationFrameId_ = null;
var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.top = 0;
canvas.style.left = 0;
canvas.style.pointerEvents = 'none';
this.canvas = canvas;
this.canvasCssWidth_ = 300;
this.canvasCssHeight_ = 150;
this.resolutionScale_ = 1;
function simpleBindShim(thisArg, func) {
return function () {
func.apply(thisArg);
};
}
this.repositionFunction_ = simpleBindShim(this, this.repositionCanvas_);
this.resizeFunction_ = simpleBindShim(this, this.resize_);
this.requestUpdateFunction_ = simpleBindShim(this, this.update_);
if (opt_options) {
this.setOptions(opt_options);
}
}
var global = typeof window === 'undefined' ? {} : window;
if (global.google && global.google.maps) {
CanvasLayer.prototype = new google.maps.OverlayView();
CanvasLayer.DEFAULT_PANE_NAME_ = 'overlayLayer';
CanvasLayer.CSS_TRANSFORM_ = function () {
var div = document.createElement('div');
var transformProps = ['transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform'];
for (var i = 0; i < transformProps.length; i++) {
var prop = transformProps[i];
if (div.style[prop] !== undefined) {
return prop;
}
}
return transformProps[0];
}();
CanvasLayer.prototype.requestAnimFrame_ = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame || global.oRequestAnimationFrame || global.msRequestAnimationFrame || function (callback) {
return global.setTimeout(callback, 1000 / 60);
};
CanvasLayer.prototype.cancelAnimFrame_ = global.cancelAnimationFrame || global.webkitCancelAnimationFrame || global.mozCancelAnimationFrame || global.oCancelAnimationFrame || global.msCancelAnimationFrame || function (requestId) {};
CanvasLayer.prototype.setOptions = function (options) {
if (options.animate !== undefined) {
this.setAnimate(options.animate);
}
if (options.paneName !== undefined) {
this.setPaneName(options.paneName);
}
if (options.updateHandler !== undefined) {
this.setUpdateHandler(options.updateHandler);
}
if (options.resizeHandler !== undefined) {
this.setResizeHandler(options.resizeHandler);
}
if (options.resolutionScale !== undefined) {
this.setResolutionScale(options.resolutionScale);
}
if (options.map !== undefined) {
this.setMap(options.map);
}
};
CanvasLayer.prototype.setAnimate = function (animate) {
this.isAnimated_ = !!animate;
if (this.isAnimated_) {
this.scheduleUpdate();
}
};
CanvasLayer.prototype.isAnimated = function () {
return this.isAnimated_;
};
CanvasLayer.prototype.setPaneName = function (paneName) {
this.paneName_ = paneName;
this.setPane_();
};
CanvasLayer.prototype.getPaneName = function () {
return this.paneName_;
};
CanvasLayer.prototype.setPane_ = function () {
if (!this.isAdded_) {
return;
}
// onAdd has been called, so panes can be used
var panes = this.getPanes();
if (!panes[this.paneName_]) {
throw new Error('"' + this.paneName_ + '" is not a valid MapPane name.');
}
panes[this.paneName_].appendChild(this.canvas);
};
CanvasLayer.prototype.setResizeHandler = function (opt_resizeHandler) {
this.resizeHandler_ = opt_resizeHandler;
};
CanvasLayer.prototype.setResolutionScale = function (scale) {
if (typeof scale === 'number') {
this.resolutionScale_ = scale;
this.resize_();
}
};
CanvasLayer.prototype.setUpdateHandler = function (opt_updateHandler) {
this.updateHandler_ = opt_updateHandler;
};
CanvasLayer.prototype.onAdd = function () {
if (this.isAdded_) {
return;
}
this.isAdded_ = true;
this.setPane_();
this.resizeListener_ = google.maps.event.addListener(this.getMap(), 'resize', this.resizeFunction_);
this.centerListener_ = google.maps.event.addListener(this.getMap(), 'center_changed', this.repositionFunction_);
this.resize_();
this.repositionCanvas_();
};
CanvasLayer.prototype.onRemove = function () {
if (!this.isAdded_) {
return;
}
this.isAdded_ = false;
this.topLeft_ = null;
// remove canvas and listeners for pan and resize from map
this.canvas.parentElement.removeChild(this.canvas);
if (this.centerListener_) {
google.maps.event.removeListener(this.centerListener_);
this.centerListener_ = null;
}
if (this.resizeListener_) {
google.maps.event.removeListener(this.resizeListener_);
this.resizeListener_ = null;
}
// cease canvas update callbacks
if (this.requestAnimationFrameId_) {
this.cancelAnimFrame_.call(global, this.requestAnimationFrameId_);
this.requestAnimationFrameId_ = null;
}
};
CanvasLayer.prototype.resize_ = function () {
if (!this.isAdded_) {
return;
}
var map = this.getMap();
var mapWidth = map.getDiv().offsetWidth;
var mapHeight = map.getDiv().offsetHeight;
var newWidth = mapWidth * this.resolutionScale_;
var newHeight = mapHeight * this.resolutionScale_;
var oldWidth = this.canvas.width;
var oldHeight = this.canvas.height;
// resizing may allocate a new back buffer, so do so conservatively
if (oldWidth !== newWidth || oldHeight !== newHeight) {
this.canvas.width = newWidth;
this.canvas.height = newHeight;
this.needsResize_ = true;
this.scheduleUpdate();
}
// reset styling if new sizes don't match; resize of data not needed
if (this.canvasCssWidth_ !== mapWidth || this.canvasCssHeight_ !== mapHeight) {
this.canvasCssWidth_ = mapWidth;
this.canvasCssHeight_ = mapHeight;
this.canvas.style.width = mapWidth + 'px';
this.canvas.style.height = mapHeight + 'px';
}
};
CanvasLayer.prototype.draw = function () {
this.repositionCanvas_();
};
CanvasLayer.prototype.repositionCanvas_ = function () {
var map = this.getMap();
// topLeft can't be calculated from map.getBounds(), because bounds are
// clamped to -180 and 180 when completely zoomed out. Instead, calculate
// left as an offset from the center, which is an unwrapped LatLng.
var top = map.getBounds().getNorthEast().lat();
var center = map.getCenter();
var scale = Math.pow(2, map.getZoom());
var left = center.lng() - this.canvasCssWidth_ * 180 / (256 * scale);
this.topLeft_ = new google.maps.LatLng(top, left);
// Canvas position relative to draggable map's container depends on
// overlayView's projection, not the map's. Have to use the center of the
// map for this, not the top left, for the same reason as above.
var projection = this.getProjection();
var divCenter = projection.fromLatLngToDivPixel(center);
var offsetX = -Math.round(this.canvasCssWidth_ / 2 - divCenter.x);
var offsetY = -Math.round(this.canvasCssHeight_ / 2 - divCenter.y);
this.canvas.style[CanvasLayer.CSS_TRANSFORM_] = 'translate(' + offsetX + 'px,' + offsetY + 'px)';
this.scheduleUpdate();
};
CanvasLayer.prototype.update_ = function () {
this.requestAnimationFrameId_ = null;
if (!this.isAdded_) {
return;
}
if (this.isAnimated_) {
this.scheduleUpdate();
}
if (this.needsResize_ && this.resizeHandler_) {
this.needsResize_ = false;
this.resizeHandler_();
}
if (this.updateHandler_) {
this.updateHandler_();
}
};
CanvasLayer.prototype.getTopLeft = function () {
return this.topLeft_;
};
CanvasLayer.prototype.scheduleUpdate = function () {
if (this.isAdded_ && !this.requestAnimationFrameId_) {
this.requestAnimationFrameId_ = this.requestAnimFrame_.call(global, this.requestUpdateFunction_);
}
};
}
function Marker(opts) {
this.city = opts.name;
this.location = new google.maps.LatLng(opts.lnglat[1], opts.lnglat[0]);
this.color = opts.color;
this.type = opts.type || 'circle';
this.speed = opts.speed || 0.15;
this.size = 0;
this.max = opts.max || 20;
}
Marker.prototype.draw = function (context) {
context.save();
context.beginPath();
switch (this.type) {
case 'circle':
this._drawCircle(context);
break;
case 'ellipse':
this._drawEllipse(context);
break;
default:
break;
}
context.closePath();
context.restore();
this.size += this.speed;
if (this.size > this.max) {
this.size = 0;
}
};
Marker.prototype._drawCircle = function (context) {
var mapProjection = map.getProjection();
var pixel = this.pixel || mapProjection.fromLatLngToPoint(this.location);
context.strokeStyle = this.color;
context.moveTo(pixel.x + pixel.size, pixel.y);
context.arc(pixel.x, pixel.y, this.size, 0, Math.PI * 2);
context.stroke();
};
Marker.prototype._drawEllipse = function (context) {
var mapProjection = map.getProjection();
var pixel = this.pixel || mapProjection.fromLatLngToPoint(this.location);
var x = pixel.x,
y = pixel.y,
w = this.size,
h = this.size / 2,
kappa = 0.5522848,
// control point offset horizontal
ox = w / 2 * kappa,
// control point offset vertical
oy = h / 2 * kappa,
// x-start
xs = x - w / 2,
// y-start
ys = y - h / 2,
// x-end
xe = x + w / 2,
// y-end
ye = y + h / 2;
context.strokeStyle = this.color;
context.moveTo(xs, y);
context.bezierCurveTo(xs, y - oy, x - ox, ys, x, ys);
context.bezierCurveTo(x + ox, ys, xe, y - oy, xe, y);
context.bezierCurveTo(xe, y + oy, x + ox, ye, x, ye);
context.bezierCurveTo(x - ox, ye, xs, y + oy, xs, y);
context.stroke();
};
function FlashMarker(map, dataSet) {
var animationLayer = null,
animationFlag = true,
markers = [];
var addMarker = function addMarker() {
if (markers.length > 0) return;
markers = [];
for (var i = 0; i < dataSet.length; i++) {
markers.push(new Marker(dataSet[i]));
}
};
//上层canvas渲染动画效果
var render = function render() {
var animationCtx = animationLayer.canvas.getContext('2d');
if (!animationCtx) {
return;
}
if (!animationFlag) {
animationCtx.clearRect(0, 0, animationCtx.canvas.width, animationCtx.canvas.height);
return;
}
addMarker();
animationCtx.fillStyle = 'rgba(0,0,0,.95)';
var prev = animationCtx.globalCompositeOperation;
animationCtx.globalCompositeOperation = 'destination-in';
animationCtx.fillRect(0, 0, animationCtx.canvas.width, animationCtx.canvas.height);
animationCtx.globalCompositeOperation = prev;
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
marker.draw(animationCtx);
}
};
//初始化
var init = function init() {
animationLayer = new CanvasLayer({
map: map,
updateHandler: render
});
// mouseInteract();
(function drawFrame() {
requestAnimationFrame(drawFrame);
render();
})();
};
init();
}
return FlashMarker;
})));