ecEffect.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /**
  2. * echarts图表特效基类
  3. *
  4. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  5. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  6. *
  7. */
  8. define(function (require) {
  9. var ecData = require('../util/ecData');
  10. var CircleShape = require('zrender/shape/Circle');
  11. var ImageShape = require('zrender/shape/Image');
  12. var curveTool = require('zrender/tool/curve');
  13. var IconShape = require('../util/shape/Icon');
  14. var SymbolShape = require('../util/shape/Symbol');
  15. var ShapeBundle = require('zrender/shape/ShapeBundle');
  16. var Polyline = require('zrender/shape/Polyline');
  17. var vec2 = require('zrender/tool/vector');
  18. var canvasSupported = require('zrender/tool/env').canvasSupported;
  19. function point(zr, effectList, shape, zlevel) {
  20. var effect = shape.effect;
  21. var color = effect.color || shape.style.strokeColor || shape.style.color;
  22. var shadowColor = effect.shadowColor || color;
  23. var size = effect.scaleSize;
  24. var distance = effect.bounceDistance;
  25. var shadowBlur = typeof effect.shadowBlur != 'undefined'
  26. ? effect.shadowBlur : size;
  27. var effectShape;
  28. if (shape.type !== 'image') {
  29. effectShape = new IconShape({
  30. zlevel : zlevel,
  31. style : {
  32. brushType : 'stroke',
  33. iconType : shape.style.iconType != 'droplet'
  34. ? shape.style.iconType
  35. : 'circle',
  36. x : shadowBlur + 1, // 线宽
  37. y : shadowBlur + 1,
  38. n : shape.style.n,
  39. width : shape.style._width * size,
  40. height : shape.style._height * size,
  41. lineWidth : 1,
  42. strokeColor : color,
  43. shadowColor : shadowColor,
  44. shadowBlur : shadowBlur
  45. },
  46. draggable : false,
  47. hoverable : false
  48. });
  49. if (shape.style.iconType == 'pin') {
  50. effectShape.style.y += effectShape.style.height / 2 * 1.5;
  51. }
  52. if (canvasSupported) { // 提高性能,换成image
  53. effectShape.style.image = zr.shapeToImage(
  54. effectShape,
  55. effectShape.style.width + shadowBlur * 2 + 2,
  56. effectShape.style.height + shadowBlur * 2 + 2
  57. ).style.image;
  58. effectShape = new ImageShape({
  59. zlevel : effectShape.zlevel,
  60. style : effectShape.style,
  61. draggable : false,
  62. hoverable : false
  63. });
  64. }
  65. }
  66. else {
  67. effectShape = new ImageShape({
  68. zlevel : zlevel,
  69. style : shape.style,
  70. draggable : false,
  71. hoverable : false
  72. });
  73. }
  74. ecData.clone(shape, effectShape);
  75. // 改变坐标,不能移到前面
  76. effectShape.position = shape.position;
  77. effectList.push(effectShape);
  78. zr.addShape(effectShape);
  79. var devicePixelRatio = shape.type !== 'image' ? (window.devicePixelRatio || 1) : 1;
  80. var offset = (effectShape.style.width / devicePixelRatio - shape.style._width) / 2;
  81. effectShape.style.x = shape.style._x - offset;
  82. effectShape.style.y = shape.style._y - offset;
  83. if (shape.style.iconType == 'pin') {
  84. effectShape.style.y -= shape.style.height / 2 * 1.5;
  85. }
  86. var duration = (effect.period + Math.random() * 10) * 100;
  87. zr.modShape(
  88. shape.id,
  89. { invisible : true}
  90. );
  91. var centerX = effectShape.style.x + (effectShape.style.width) / 2 / devicePixelRatio;
  92. var centerY = effectShape.style.y + (effectShape.style.height) / 2 / devicePixelRatio;
  93. if (effect.type === 'scale') {
  94. // 放大效果
  95. zr.modShape(
  96. effectShape.id,
  97. {
  98. scale : [0.1, 0.1, centerX, centerY]
  99. }
  100. );
  101. zr.animate(effectShape.id, '', effect.loop)
  102. .when(
  103. duration,
  104. {
  105. scale : [1, 1, centerX, centerY]
  106. }
  107. )
  108. .done(function() {
  109. shape.effect.show = false;
  110. zr.delShape(effectShape.id);
  111. })
  112. .start();
  113. }
  114. else {
  115. zr.animate(effectShape.id, 'style', effect.loop)
  116. .when(
  117. duration,
  118. {
  119. y : effectShape.style.y - distance
  120. }
  121. )
  122. .when(
  123. duration * 2,
  124. {
  125. y : effectShape.style.y
  126. }
  127. )
  128. .done(function() {
  129. shape.effect.show = false;
  130. zr.delShape(effectShape.id);
  131. })
  132. .start();
  133. }
  134. }
  135. function largePoint(zr, effectList, shape, zlevel) {
  136. var effect = shape.effect;
  137. var color = effect.color || shape.style.strokeColor || shape.style.color;
  138. var size = effect.scaleSize;
  139. var shadowColor = effect.shadowColor || color;
  140. var shadowBlur = typeof effect.shadowBlur != 'undefined'
  141. ? effect.shadowBlur : (size * 2);
  142. var devicePixelRatio = window.devicePixelRatio || 1;
  143. var effectShape = new SymbolShape({
  144. zlevel : zlevel,
  145. position : shape.position,
  146. scale : shape.scale,
  147. style : {
  148. pointList : shape.style.pointList,
  149. iconType : shape.style.iconType,
  150. color : color,
  151. strokeColor : color,
  152. shadowColor : shadowColor,
  153. shadowBlur : shadowBlur * devicePixelRatio,
  154. random : true,
  155. brushType: 'fill',
  156. lineWidth:1,
  157. size : shape.style.size
  158. },
  159. draggable : false,
  160. hoverable : false
  161. });
  162. effectList.push(effectShape);
  163. zr.addShape(effectShape);
  164. zr.modShape(
  165. shape.id,
  166. { invisible : true}
  167. );
  168. var duration = Math.round(effect.period * 100);
  169. var clip1 = {};
  170. var clip2 = {};
  171. for (var i = 0; i < 20; i++) {
  172. effectShape.style['randomMap' + i] = 0;
  173. clip1 = {};
  174. clip1['randomMap' + i] = 100;
  175. clip2 = {};
  176. clip2['randomMap' + i] = 0;
  177. effectShape.style['randomMap' + i] = Math.random() * 100;
  178. zr.animate(effectShape.id, 'style', true)
  179. .when(duration, clip1)
  180. .when(duration * 2, clip2)
  181. .when(duration * 3, clip1)
  182. .when(duration * 4, clip1)
  183. .delay(Math.random() * duration * i)
  184. //.delay(duration / 15 * (15 - i + 1))
  185. .start();
  186. }
  187. }
  188. function line(zr, effectList, shape, zlevel, isLarge) {
  189. var effect = shape.effect;
  190. var shapeStyle = shape.style;
  191. var color = effect.color || shapeStyle.strokeColor || shapeStyle.color;
  192. var shadowColor = effect.shadowColor || shapeStyle.strokeColor || color;
  193. var size = shapeStyle.lineWidth * effect.scaleSize;
  194. var shadowBlur = typeof effect.shadowBlur != 'undefined'
  195. ? effect.shadowBlur : size;
  196. var effectShape = new CircleShape({
  197. zlevel : zlevel,
  198. style : {
  199. x : shadowBlur,
  200. y : shadowBlur,
  201. r : size,
  202. color : color,
  203. shadowColor : shadowColor,
  204. shadowBlur : shadowBlur
  205. },
  206. hoverable : false
  207. });
  208. var offset = 0;
  209. if (canvasSupported && ! isLarge) { // 提高性能,换成image
  210. var zlevel = effectShape.zlevel;
  211. effectShape = zr.shapeToImage(
  212. effectShape,
  213. (size + shadowBlur) * 2,
  214. (size + shadowBlur) * 2
  215. );
  216. effectShape.zlevel = zlevel;
  217. effectShape.hoverable = false;
  218. offset = shadowBlur;
  219. }
  220. if (! isLarge) {
  221. ecData.clone(shape, effectShape);
  222. // 改变坐标, 不能移到前面
  223. effectShape.position = shape.position;
  224. effectList.push(effectShape);
  225. zr.addShape(effectShape);
  226. }
  227. var effectDone = function () {
  228. if (! isLarge) {
  229. shape.effect.show = false;
  230. zr.delShape(effectShape.id);
  231. }
  232. effectShape.effectAnimator = null;
  233. };
  234. if (shape instanceof Polyline) {
  235. var distanceList = [0];
  236. var totalDist = 0;
  237. var pointList = shapeStyle.pointList;
  238. var controlPointList = shapeStyle.controlPointList;
  239. for (var i = 1; i < pointList.length; i++) {
  240. if (controlPointList) {
  241. var cp1 = controlPointList[(i - 1) * 2];
  242. var cp2 = controlPointList[(i - 1) * 2 + 1];
  243. totalDist += vec2.dist(pointList[i - 1], cp1)
  244. + vec2.dist(cp1, cp2)
  245. + vec2.dist(cp2, pointList[i]);
  246. }
  247. else {
  248. totalDist += vec2.dist(pointList[i - 1], pointList[i]);
  249. }
  250. distanceList.push(totalDist);
  251. }
  252. var obj = { p: 0 };
  253. var animator = zr.animation.animate(obj, { loop: effect.loop });
  254. for (var i = 0; i < distanceList.length; i++) {
  255. animator.when(distanceList[i] * effect.period, { p: i });
  256. }
  257. animator.during(function () {
  258. var i = Math.floor(obj.p);
  259. var x, y;
  260. if (i == pointList.length - 1) {
  261. x = pointList[i][0];
  262. y = pointList[i][1];
  263. }
  264. else {
  265. var t = obj.p - i;
  266. var p0 = pointList[i];
  267. var p1 = pointList[i + 1];
  268. if (controlPointList) {
  269. var cp1 = controlPointList[i * 2];
  270. var cp2 = controlPointList[i * 2 + 1];
  271. x = curveTool.cubicAt(
  272. p0[0], cp1[0], cp2[0], p1[0], t
  273. );
  274. y = curveTool.cubicAt(
  275. p0[1], cp1[1], cp2[1], p1[1], t
  276. );
  277. }
  278. else {
  279. x = (p1[0] - p0[0]) * t + p0[0];
  280. y = (p1[1] - p0[1]) * t + p0[1];
  281. }
  282. }
  283. effectShape.style.x = x;
  284. effectShape.style.y = y;
  285. if (! isLarge) {
  286. zr.modShape(effectShape);
  287. }
  288. })
  289. .done(effectDone)
  290. .start();
  291. animator.duration = totalDist * effect.period;
  292. effectShape.effectAnimator = animator;
  293. }
  294. else {
  295. var x0 = shapeStyle.xStart - offset;
  296. var y0 = shapeStyle.yStart - offset;
  297. var x2 = shapeStyle.xEnd - offset;
  298. var y2 = shapeStyle.yEnd - offset;
  299. effectShape.style.x = x0;
  300. effectShape.style.y = y0;
  301. var distance = (x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0);
  302. var duration = Math.round(Math.sqrt(Math.round(
  303. distance * effect.period * effect.period
  304. )));
  305. if (shape.style.curveness > 0) {
  306. var x1 = shapeStyle.cpX1 - offset;
  307. var y1 = shapeStyle.cpY1 - offset;
  308. effectShape.effectAnimator = zr.animation.animate(effectShape, { loop: effect.loop })
  309. .when(duration, { p: 1 })
  310. .during(function (target, t) {
  311. effectShape.style.x = curveTool.quadraticAt(
  312. x0, x1, x2, t
  313. );
  314. effectShape.style.y = curveTool.quadraticAt(
  315. y0, y1, y2, t
  316. );
  317. if (! isLarge) {
  318. zr.modShape(effectShape);
  319. }
  320. })
  321. .done(effectDone)
  322. .start();
  323. }
  324. else {
  325. // 不用 zr.animate,因为在用 ShapeBundle 的时候单个 effectShape 不会
  326. // 被加到 zrender 中
  327. effectShape.effectAnimator = zr.animation.animate(effectShape.style, { loop: effect.loop })
  328. .when(duration, {
  329. x: x2,
  330. y: y2
  331. })
  332. .during(function () {
  333. if (! isLarge) {
  334. zr.modShape(effectShape);
  335. }
  336. })
  337. .done(effectDone)
  338. .start();
  339. }
  340. effectShape.effectAnimator.duration = duration;
  341. }
  342. return effectShape;
  343. }
  344. function largeLine(zr, effectList, shape, zlevel) {
  345. var effectShape = new ShapeBundle({
  346. style: {
  347. shapeList: []
  348. },
  349. zlevel: zlevel,
  350. hoverable: false
  351. });
  352. var shapeList = shape.style.shapeList;
  353. var effect = shape.effect;
  354. effectShape.position = shape.position;
  355. var maxDuration = 0;
  356. var subEffectAnimators = [];
  357. for (var i = 0; i < shapeList.length; i++) {
  358. shapeList[i].effect = effect;
  359. var subEffectShape = line(zr, null, shapeList[i], zlevel, true);
  360. var subEffectAnimator = subEffectShape.effectAnimator;
  361. effectShape.style.shapeList.push(subEffectShape);
  362. if (subEffectAnimator.duration > maxDuration) {
  363. maxDuration = subEffectAnimator.duration;
  364. }
  365. if (i === 0) {
  366. effectShape.style.color = subEffectShape.style.color;
  367. effectShape.style.shadowBlur = subEffectShape.style.shadowBlur;
  368. effectShape.style.shadowColor = subEffectShape.style.shadowColor;
  369. }
  370. subEffectAnimators.push(subEffectAnimator);
  371. }
  372. effectList.push(effectShape);
  373. zr.addShape(effectShape);
  374. var clearAllAnimators = function () {
  375. for (var i = 0; i < subEffectAnimators.length; i++) {
  376. subEffectAnimators[i].stop();
  377. }
  378. };
  379. if (maxDuration) {
  380. effectShape.__dummy = 0;
  381. // Proxy animator
  382. var animator = zr.animate(effectShape.id, '', effect.loop)
  383. .when(maxDuration, {
  384. __dummy: 1
  385. })
  386. .during(function () {
  387. zr.modShape(effectShape);
  388. })
  389. .done(function () {
  390. shape.effect.show = false;
  391. zr.delShape(effectShape.id);
  392. })
  393. .start();
  394. var oldStop = animator.stop;
  395. animator.stop = function () {
  396. clearAllAnimators();
  397. oldStop.call(this);
  398. };
  399. }
  400. }
  401. return {
  402. point : point,
  403. largePoint : largePoint,
  404. line : line,
  405. largeLine: largeLine
  406. };
  407. });