map-flashmarker.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.FlashMarker = factory());
  5. }(this, (function () { 'use strict';
  6. /**
  7. * @author https://github.com/chengquan223
  8. * @Date 2017-02-27
  9. * */
  10. function CanvasLayer(options) {
  11. this.options = options || {};
  12. this.paneName = this.options.paneName || 'labelPane';
  13. this.zIndex = this.options.zIndex || 0;
  14. this._map = options.map;
  15. this._lastDrawTime = null;
  16. this.show();
  17. }
  18. CanvasLayer.prototype = new BMap.Overlay();
  19. CanvasLayer.prototype.initialize = function (map) {
  20. this._map = map;
  21. var canvas = this.canvas = document.createElement('canvas');
  22. var ctx = this.ctx = this.canvas.getContext('2d');
  23. canvas.style.cssText = 'position:absolute;' + 'left:0;' + 'top:0;' + 'z-index:' + this.zIndex + ';';
  24. this.adjustSize();
  25. this.adjustRatio(ctx);
  26. map.getPanes()[this.paneName].appendChild(canvas);
  27. var that = this;
  28. map.addEventListener('resize', function () {
  29. that.adjustSize();
  30. that._draw();
  31. });
  32. return this.canvas;
  33. };
  34. CanvasLayer.prototype.adjustSize = function () {
  35. var size = this._map.getSize();
  36. var canvas = this.canvas;
  37. canvas.width = size.width;
  38. canvas.height = size.height;
  39. canvas.style.width = canvas.width + 'px';
  40. canvas.style.height = canvas.height + 'px';
  41. };
  42. CanvasLayer.prototype.adjustRatio = function (ctx) {
  43. var backingStore = ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
  44. var pixelRatio = (window.devicePixelRatio || 1) / backingStore;
  45. var canvasWidth = ctx.canvas.width;
  46. var canvasHeight = ctx.canvas.height;
  47. ctx.canvas.width = canvasWidth * pixelRatio;
  48. ctx.canvas.height = canvasHeight * pixelRatio;
  49. ctx.canvas.style.width = canvasWidth + 'px';
  50. ctx.canvas.style.height = canvasHeight + 'px';
  51. // console.log(ctx.canvas.height, canvasHeight);
  52. ctx.scale(pixelRatio, pixelRatio);
  53. };
  54. CanvasLayer.prototype.draw = function () {
  55. var self = this;
  56. var args = arguments;
  57. clearTimeout(self.timeoutID);
  58. self.timeoutID = setTimeout(function () {
  59. self._draw();
  60. }, 15);
  61. };
  62. CanvasLayer.prototype._draw = function () {
  63. var map = this._map;
  64. var size = map.getSize();
  65. var center = map.getCenter();
  66. if (center) {
  67. var pixel = map.pointToOverlayPixel(center);
  68. this.canvas.style.left = pixel.x - size.width / 2 + 'px';
  69. this.canvas.style.top = pixel.y - size.height / 2 + 'px';
  70. this.dispatchEvent('draw');
  71. this.options.update && this.options.update.call(this);
  72. }
  73. };
  74. CanvasLayer.prototype.getContainer = function () {
  75. return this.canvas;
  76. };
  77. CanvasLayer.prototype.show = function () {
  78. if (!this.canvas) {
  79. this._map.addOverlay(this);
  80. }
  81. this.canvas.style.display = 'block';
  82. };
  83. CanvasLayer.prototype.hide = function () {
  84. this.canvas.style.display = 'none';
  85. //this._map.removeOverlay(this);
  86. };
  87. CanvasLayer.prototype.setZIndex = function (zIndex) {
  88. this.canvas.style.zIndex = zIndex;
  89. };
  90. CanvasLayer.prototype.getZIndex = function () {
  91. return this.zIndex;
  92. };
  93. var global = typeof window === 'undefined' ? {} : window;
  94. var requestAnimationFrame = global.requestAnimationFrame || global.mozRequestAnimationFrame || global.webkitRequestAnimationFrame || global.msRequestAnimationFrame || function (callback) {
  95. return global.setTimeout(callback, 1000 / 60);
  96. };
  97. function Marker(opts) {
  98. this.city = opts.name;
  99. this.location = new BMap.Point(opts.lnglat[0], opts.lnglat[1]);
  100. this.color = opts.color;
  101. this.type = opts.type || 'circle';
  102. this.speed = opts.speed || 0.15;
  103. this.size = 0;
  104. this.max = opts.max || 20;
  105. }
  106. Marker.prototype.draw = function (context) {
  107. context.save();
  108. context.beginPath();
  109. switch (this.type) {
  110. case 'circle':
  111. this._drawCircle(context);
  112. break;
  113. case 'ellipse':
  114. this._drawEllipse(context);
  115. break;
  116. default:
  117. break;
  118. }
  119. context.closePath();
  120. context.restore();
  121. this.size += this.speed;
  122. if (this.size > this.max) {
  123. this.size = 2;
  124. }
  125. };
  126. Marker.prototype._drawCircle = function (context) {
  127. var pixel = this.pixel || map.pointToPixel(this.location);
  128. context.strokeStyle = this.color;
  129. context.moveTo(pixel.x + pixel.size, pixel.y);
  130. context.arc(pixel.x, pixel.y, this.size+1, 0, Math.PI * 2);
  131. context.stroke();
  132. context.beginPath()
  133. context.fillStyle = this.color;
  134. context.arc(pixel.x, pixel.y, 2, 0, Math.PI * 2);
  135. context.fill();
  136. };
  137. Marker.prototype._drawEllipse = function (context) {
  138. var pixel = this.pixel || map.pointToPixel(this.location);
  139. var x = pixel.x,
  140. y = pixel.y,
  141. w = this.size,
  142. h = this.size / 2,
  143. kappa = 0.5522848,
  144. // control point offset horizontal
  145. ox = w / 2 * kappa,
  146. // control point offset vertical
  147. oy = h / 2 * kappa,
  148. // x-start
  149. xs = x - w / 2,
  150. // y-start
  151. ys = y - h / 2,
  152. // x-end
  153. xe = x + w / 2,
  154. // y-end
  155. ye = y + h / 2;
  156. context.strokeStyle = this.color;
  157. context.moveTo(xs, y);
  158. context.bezierCurveTo(xs, y - oy, x - ox, ys, x, ys);
  159. context.bezierCurveTo(x + ox, ys, xe, y - oy, xe, y);
  160. context.bezierCurveTo(xe, y + oy, x + ox, ye, x, ye);
  161. context.bezierCurveTo(x - ox, ye, xs, y + oy, xs, y);
  162. context.stroke();
  163. };
  164. function FlashMarker(map, dataSet) {
  165. var animationLayer = null,
  166. width = map.getSize().width,
  167. height = map.getSize().height,
  168. animationFlag = true,
  169. markers = [];
  170. var addMarker = function addMarker() {
  171. if (markers.length > 0) return;
  172. markers = [];
  173. for (var i = 0; i < dataSet.length; i++) {
  174. markers.push(new Marker(dataSet[i]));
  175. }
  176. };
  177. //上层canvas渲染,动画效果
  178. var render = function render() {
  179. var animationCtx = animationLayer.canvas.getContext('2d');
  180. if (!animationCtx) {
  181. return;
  182. }
  183. if (!animationFlag) {
  184. animationCtx.clearRect(0, 0, width, height);
  185. return;
  186. }
  187. addMarker();
  188. animationCtx.fillStyle = 'rgba(0,0,0,.85)';
  189. var prev = animationCtx.globalCompositeOperation;
  190. animationCtx.globalCompositeOperation = 'destination-in';
  191. animationCtx.fillRect(0, 0, width, height);
  192. animationCtx.globalCompositeOperation = prev;
  193. for (var i = 0; i < markers.length; i++) {
  194. var marker = markers[i];
  195. marker.draw(animationCtx);
  196. }
  197. };
  198. //鼠标事件
  199. var mouseInteract = function mouseInteract() {
  200. map.addEventListener('movestart', function () {
  201. animationFlag = false;
  202. });
  203. map.addEventListener('moveend', function () {
  204. animationFlag = true;
  205. markers = []; //解决拖动后多余的小圆点bug,没想明白,暂时这样
  206. });
  207. map.addEventListener('zoomstart', function () {
  208. animationFlag = false;
  209. });
  210. map.addEventListener('zoomend', function () {
  211. animationFlag = true;
  212. markers = [];
  213. });
  214. };
  215. //初始化
  216. var init = function init() {
  217. animationLayer = new CanvasLayer({
  218. map: map,
  219. update: render
  220. });
  221. mouseInteract();
  222. (function drawFrame() {
  223. requestAnimationFrame(drawFrame);
  224. render();
  225. })();
  226. };
  227. init();
  228. }
  229. return FlashMarker;
  230. })));