wc-motion-chart.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. (function ($) {
  2. function WcChart(config) {
  3. this.init(config);
  4. }
  5. WcChart.prototype = {
  6. /**
  7. * margin of chart
  8. */
  9. margin: 10,
  10. /**
  11. * Initial width
  12. * @type {number}
  13. */
  14. width: 0,
  15. /**
  16. * Initial height
  17. * @type {number}
  18. */
  19. height: 0,
  20. /**
  21. * Is data has loaded
  22. * @type {false}
  23. */
  24. isDataLoad: false,
  25. /**
  26. * Initial of chart data
  27. * @type {Array}
  28. */
  29. data: null,
  30. /**
  31. * data format, it will be init by init function
  32. * @type {Array}
  33. */
  34. points: [],
  35. /**
  36. * font family
  37. * @type {String}
  38. */
  39. fontFamily: 'sans-serif,arial',
  40. /**
  41. * Initial end day
  42. * @type {Date}
  43. */
  44. day: null,
  45. dateArr:[],
  46. dateType:null,
  47. /**
  48. * Initial of chart y-axis limit
  49. * @type {number}
  50. */
  51. yAxis: 16000,
  52. /**
  53. * Initial of chart y-axis increase unit
  54. * @type {number}
  55. */
  56. yAxisIc: 4000,
  57. /**
  58. * Background quad angle radius
  59. * @type {number}
  60. */
  61. quadRadius: 10,
  62. /**
  63. * head left text
  64. * @type {String}
  65. */
  66. headText: "",
  67. /**
  68. * chart font size
  69. * @type {Number}
  70. */
  71. chartFontSize: 10,
  72. /**
  73. * 10 thousand y-axis height
  74. * @type {Number}
  75. */
  76. chartMeanLine : 0,
  77. /**
  78. * rank reference, a json object
  79. * - null: means never mind it
  80. * - normal json data
  81. * - { height: 30, avatar: Image, title : 'xxx get first', url: 'http://'}
  82. * @type {Object}
  83. */
  84. rankRef: null,
  85. rankPadding: 5,
  86. rankImgPattern: null,
  87. /**
  88. * rectangles
  89. * - {x: 0, y: 0, width: 0, height: 0}
  90. * @type {Object}
  91. */
  92. rectHead: {x: 0, y: 0, width: 0, height: 0},
  93. rectChart: {x: 0, y: 0, width: 0, height: 0},
  94. rectChartCenter: {x: 0, y: 0, width: 0, height: 0},
  95. rectRank: {x: 0, y: 0, width: 0, height: 0},
  96. rectRankAvatar: {x: 0, y: 0, width: 0, height: 0},
  97. rectRankBtn: {x: 0, y: 0, width: 0, height: 0},
  98. rectRankText: {x: 0, y: 0, width: 0, height: 0},
  99. /**
  100. * This is the only required option. It should be from 0.0 to 1.0
  101. * @type {number}
  102. */
  103. value: 1,
  104. /**
  105. * Fill of the arc. You may set it to:
  106. * - solid color:
  107. * - { color: '#3aeabb' }
  108. * - { color: 'rgba(255, 255, 255, .3)' }
  109. * - linear gradient (left to right):
  110. * - { gradient: ['#3aeabb', '#fdd250'], gradientAngle: Math.PI / 4 }
  111. * - { gradient: ['red', 'green', 'blue'], gradientDirection: [x0, y0, x1, y1] }
  112. * - image:
  113. * - { image: 'http://i.imgur.com/pT0i89v.png' }
  114. * - { image: imageObject }
  115. * - { color: 'lime', image: 'http://i.imgur.com/pT0i89v.png' } - color displayed until the image is loaded
  116. */
  117. fill: {
  118. gradient: ['#3aeabb', '#fdd250']
  119. },
  120. /**
  121. * Animation config (see jQuery animations: http://api.jquery.com/animate/)
  122. */
  123. animation: {
  124. duration: 400,
  125. easing: 'wcChart'
  126. },
  127. /**
  128. * Default animation starts at 0.0 and ends at specified `value`. Let's call this direct animation.
  129. * If you want to make reversed animation then you should set `animationStartValue` to 1.0.
  130. * Also you may specify any other value from 0.0 to 1.0
  131. * @type {number}
  132. */
  133. animationStartValue: 0.0,
  134. /**
  135. * @type {number}
  136. */
  137. animationPoint: null,
  138. /**
  139. * Constructor of wechat chart
  140. */
  141. constructor: WcChart,
  142. /**
  143. * Container element. Should be passed into constructor config
  144. * @type {jQuery}
  145. */
  146. el: null,
  147. /**
  148. * Canvas element.
  149. * @type {HTMLCanvasElement}
  150. */
  151. canvas: null,
  152. /**
  153. * 2D-context of the canvas
  154. * @protected
  155. * @type {CanvasRenderingContext2D}
  156. */
  157. ctx: null,
  158. /**
  159. * Fill of the background
  160. * @type {string|CanvasGradient|CanvasPattern}
  161. */
  162. fillPattern: null,
  163. /**
  164. * Last rendered frame value
  165. * @type {number}
  166. */
  167. lastFrameValue: 0.0,
  168. /**
  169. * Init/re-init the widget
  170. * @param {object} config Config
  171. */
  172. init: function (config) {
  173. $.extend(this, config);
  174. if (config.data) {
  175. this.isDataLoad = true;
  176. }
  177. this.initWidget();
  178. this.initRect();
  179. this.initData();
  180. this.initRank();
  181. this.initFill();
  182. this.draw();
  183. if(this.event == 'tap'){
  184. this.el.on('tap', this.clickFuc);
  185. }else{
  186. this.el.click(this.clickFuc);
  187. }
  188. },
  189. /**
  190. * Init widget
  191. * @protected
  192. */
  193. initWidget: function () {
  194. var jEl = $(this.el),
  195. canvas = this.canvas = this.canvas || jEl[0];
  196. canvas.width = this.width = this.width == 0 ? jEl.width() : this.width;
  197. canvas.height = this.height = this.height == 0 ? jEl.height() : this.height;
  198. this.ctx = canvas.getContext('2d');
  199. },
  200. /**
  201. * Init rectangles
  202. */
  203. initRect: function () {
  204. var margin = this.margin;
  205. var titleHeight = 35;
  206. var rankHeight = 0;
  207. if (this.rankRef) {
  208. rankHeight = this.rankRef.height;
  209. }
  210. this.rectHead = {x: 0, y: 0, width: this.width, height: titleHeight};
  211. this.rectChart = {
  212. x: margin, y: titleHeight,
  213. width: this.width - 2 * margin,
  214. height: this.height - titleHeight - rankHeight
  215. };
  216. this.rectChartCenter = {
  217. x: this.rectChart.x,
  218. y: this.rectChart.y + this.chartFontSize * 2.5,
  219. width: this.rectChart.width - this.chartFontSize * 0.8,
  220. height: this.rectChart.height - this.chartFontSize * 5,
  221. };
  222. this.rectRank = {
  223. x: margin, y: this.height - rankHeight,
  224. width: this.width - 2 * margin,
  225. height: rankHeight
  226. };
  227. this.rectRankAvatar = {
  228. x: this.rectRank.x,
  229. y: this.rectRank.y,
  230. width: this.rectRank.height,
  231. height: this.rectRank.height
  232. };
  233. this.rectRankBtn = {
  234. x: this.rectRank.width - this.rectRank.height,
  235. y: this.rectRank.y,
  236. width: this.rectRank.height,
  237. height: this.rectRank.height
  238. };
  239. this.rectRankText = {
  240. x: this.rectRankAvatar.x + this.rectRankAvatar.width,
  241. y: this.rectRank.y,
  242. width: this.rectRank.width - 2 * this.rectRank.height,
  243. height: this.rectRank.height
  244. };
  245. },
  246. /**
  247. * init all data
  248. */
  249. initData: function () {
  250. if (!$.isArray(this.data) || this.isDataLoad == false) {
  251. this.data = [0, 0, 0, 0, 0, 0];
  252. }
  253. if (this.day == null) {
  254. this.day = new Date();
  255. }
  256. /* get limit and last data */
  257. var maxData = Math.max.apply(Math, this.data),
  258. itrDay = this.day,
  259. yMaxUint = maxData <= this.yAxis ? this.yAxis :
  260. Math.ceil((maxData - this.yAxis) / this.yAxisIc) * this.yAxisIc + this.yAxis;
  261. var interval = this.rectChartCenter.width / (this.data.length - 1);
  262. if(this.data.length==1){//只有一条数据时,点居中显示
  263. interval = this.rectChartCenter.width/2;
  264. }
  265. /* init begin date and prepare for iteration */
  266. // itrDay.setDate(this.day.getDate() - this.data.length + 1);
  267. /* find out y-axis point of 10 thousand unit line */
  268. this.chartMeanLine = this.rectChartCenter.y + this.rectChartCenter.height
  269. - this.yAxis * this.rectChartCenter.height / yMaxUint;
  270. /* transfer data into points */
  271. var textStr = "";
  272. for (var i = 0; i < this.data.length; i++) {
  273. if(this.dateType=="3"){//月
  274. if(this.dateArr.length>0){
  275. var month = parseInt(this.dateArr[i].split("-")[0]);
  276. textStr = month+ "月";
  277. }
  278. }else{//日、周
  279. if(this.dateArr.length>0){
  280. var month="",day="";
  281. if(i==0){
  282. month = parseInt(this.dateArr[0].split("-")[0]);
  283. day = parseInt(this.dateArr[0].split("-")[1]);
  284. }else{
  285. month = parseInt(this.dateArr[i].split("-")[0]);
  286. day = parseInt(this.dateArr[i].split("-")[1]);
  287. }
  288. textStr = i == 0 ? month+ "月" + day: day;
  289. }else{
  290. textStr = i == 0 ? (itrDay.getMonth() + 1) + "月" + itrDay.getDate() : itrDay.getDate();
  291. }
  292. }
  293. var x = this.rectChartCenter.x + interval * i;
  294. if(this.data.length==1){//只有一条数据时,点居中显示
  295. x = interval;
  296. }
  297. this.points[i] = {
  298. x: x,
  299. y: this.rectChartCenter.y + this.rectChartCenter.height
  300. - this.data[i] * this.rectChartCenter.height / yMaxUint,
  301. value: this.data[i],
  302. text:textStr,
  303. radius: 6,
  304. textAlign: i == 0 ? 'left' : 'center',
  305. rect: {x: this.rectChartCenter.x + interval * (i - 0.5), y: this.rectChart.y,
  306. width: interval, height: this.rectChart.height}
  307. };
  308. itrDay.setDate(itrDay.getDate() + 1);
  309. }
  310. },
  311. /**
  312. * init rank params
  313. */
  314. initRank: function () {
  315. if (this.rankRef == null) {
  316. return;
  317. }
  318. if (this.rankRef.avatar) {
  319. var img = this.rankRef.avatar;
  320. img.height = this.rankRef.height - this.rankPadding * 2;
  321. img.width = img.height;
  322. this.rankImgPattern = this.ctx.createPattern(this.rankRef.avatar, 'no-repeat');
  323. /* redraw when image load in same case */
  324. var instance = this;
  325. this.rankRef.avatar.onload = function() {
  326. instance.draw();
  327. }
  328. }
  329. },
  330. /**
  331. * Init fill pattern
  332. * It could do this async (on image load)
  333. */
  334. initFill: function () {
  335. var self = this,
  336. fill = this.fill,
  337. ctx = this.ctx,
  338. width = this.width,
  339. height = this.height;
  340. if (!fill)
  341. throw Error("The fill is not specified!");
  342. if (fill.color)
  343. this.fillPattern = fill.color;
  344. if (fill.gradient) {
  345. var gr = fill.gradient;
  346. if (gr.length == 1) {
  347. this.fillPattern = gr[0];
  348. } else if (gr.length > 1) {
  349. var ga = fill.gradientAngle || 0, // gradient direction angle; 0 by default
  350. gd = fill.gradientDirection || [
  351. width / 2 * (1 - Math.cos(ga)), // x0
  352. height / 2 * (1 + Math.sin(ga)), // y0
  353. width / 2 * (1 + Math.cos(ga)), // x1
  354. height / 2 * (1 - Math.sin(ga)) // y1
  355. ];
  356. var lg = ctx.createLinearGradient.apply(ctx, gd);
  357. for (var i = 0; i < gr.length; i++) {
  358. var color = gr[i],
  359. pos = i / (gr.length - 1);
  360. if ($.isArray(color)) {
  361. pos = color[1];
  362. color = color[0];
  363. }
  364. lg.addColorStop(pos, color);
  365. }
  366. this.fillPattern = lg;
  367. }
  368. }
  369. },
  370. draw: function () {
  371. if (this.animation)
  372. this.drawAnimated(this.value);
  373. else
  374. this.drawFrame(this.value);
  375. },
  376. /**
  377. * draw a frame
  378. * @param {number} v Frame value
  379. */
  380. drawFrame: function (v) {
  381. this.lastFrameValue = v;
  382. //this.ctx.clearRect(0, 0, this.width, this.height);
  383. this.ctx.fillStyle = "white";
  384. this.ctx.strokeStyle="white";
  385. this.drawBack();
  386. this.drawHead();
  387. this.drawChart();
  388. this.drawStep(v);
  389. this.drawRank();
  390. },
  391. /**
  392. * draw background
  393. */
  394. drawBack: function () {
  395. var ctx = this.ctx;
  396. ctx.save();
  397. ctx.fillStyle = this.fillPattern;
  398. ctx.globalAlpha = 1;
  399. ctx.roundRect(0, 0, this.width-5, this.height, this.quadRadius, true, false);
  400. ctx.restore();
  401. },
  402. /**
  403. * draw head
  404. */
  405. drawHead: function () {
  406. var fontSize = 25,
  407. ctx = this.ctx;
  408. /* draw text of head */
  409. ctx.save();
  410. ctx.globalAlpha = 1;
  411. ctx.font = fontSize + "px " + this.fontFamily;
  412. ctx.fillStyle = "white";
  413. ctx.fillText(this.headText, this.rectHead.x, this.rectHead.y + fontSize + this.margin,
  414. this.rectHead.width);
  415. ctx.textAlign = "center";
  416. ctx.fillText("",//单位/人
  417. this.rectHead.x + this.rectHead.width,
  418. this.rectHead.y + fontSize + this.margin);
  419. /* draw a split line
  420. ctx.beginPath();
  421. ctx.globalAlpha = 0.8;
  422. ctx.moveTo(this.rectHead.x, this.rectHead.y + this.rectHead.height);
  423. ctx.lineTo(this.rectHead.x + this.rectHead.width, this.rectHead.y + this.rectHead.height);
  424. ctx.stroke();*/
  425. ctx.restore();
  426. },
  427. /* draw chart */
  428. drawChart: function () {
  429. var ctx = this.ctx;
  430. ctx.save();
  431. ctx.fillStyle = "white";
  432. /* draw 10 thousand line of x-axis */
  433. ctx.globalAlpha = 1;
  434. ctx.font = "12px " + this.fontFamily;
  435. // ctx.fillText(this.yAxis, this.rectChartCenter.x + this.rectChartCenter.width-30,
  436. // this.chartMeanLine + this.chartFontSize / 2.8);
  437. ctx.fillText(this.yAxis, 0,
  438. this.chartMeanLine + this.chartFontSize / 2.8);
  439. ctx.beginPath();
  440. ctx.lineWidth = 1;
  441. ctx.dashedLineTo(this.rectChartCenter.x+35, this.chartMeanLine,
  442. this.rectChartCenter.x + this.rectChartCenter.width+10, this.chartMeanLine, [7, 4]);
  443. ctx.stroke();
  444. /* draw x-axis text and point */
  445. ctx.font = this.chartFontSize + "px " + this.fontFamily;
  446. for (var i = 0; i < this.points.length; i++) {
  447. /* draw text */
  448. var xPos = i==0? this.points[i].x-10: this.points[i].x;
  449. ctx.textAlign = this.points[i].textAlign;
  450. ctx.globalAlpha = i == this.points.length - 1 ? 1 :
  451. i == this.animationPoint ? 1 : 0.8;
  452. ctx.fillText(this.points[i].text, xPos,
  453. this.rectChartCenter.y + this.rectChartCenter.height + 1.5 * this.chartFontSize);
  454. }
  455. /* out if data unload */
  456. if (this.isDataLoad == false) {
  457. ctx.restore();
  458. return;
  459. }
  460. /* draw points and lines */
  461. for (i = 0; i < this.points.length; i++) {
  462. /* draw point */
  463. ctx.globalAlpha = 1;
  464. ctx.beginPath();
  465. ctx.arc(this.points[i].x, this.points[i].y, this.points[i].radius, 0, 2 * Math.PI);
  466. ctx.fill();
  467. /* draw line */
  468. if (i != 0) {
  469. ctx.save();
  470. ctx.beginPath();
  471. ctx.lineWidth = 2;
  472. ctx.moveTo(this.points[i - 1].x, this.points[i - 1].y);
  473. ctx.lineTo(this.points[i].x, this.points[i].y);
  474. /*if (this.points[i - 1].value != 0) {
  475. ctx.lineTo(this.points[i].x, this.points[i].y);
  476. } else {
  477. ctx.globalAlpha = 0.5;
  478. ctx.dashedLineTo(this.points[i-1].x, this.points[i-1].y,
  479. this.points[i].x, this.points[i].y, 7);
  480. }*/
  481. ctx.stroke();
  482. ctx.restore();
  483. }
  484. }
  485. /* draw a shadow */
  486. ctx.beginPath();
  487. ctx.moveTo(this.points[0].x, this.points[0].y);
  488. for (i = 1; i < this.points.length; i++) {
  489. ctx.lineTo(this.points[i].x, this.points[i].y);
  490. }
  491. ctx.lineTo(this.rectChartCenter.x + this.rectChartCenter.width,
  492. this.rectChartCenter.y + this.rectChartCenter.height);
  493. ctx.lineTo(this.rectChartCenter.x, this.rectChartCenter.y + this.rectChartCenter.height);
  494. ctx.lineTo(this.points[0].x, this.points[0].y);
  495. ctx.fillStyle="white";
  496. ctx.globalAlpha = 0.1;
  497. ctx.fill();
  498. ctx.restore();
  499. },
  500. /* draw animation step */
  501. drawStep: function(v) {
  502. if (this.animationPoint == null || this.animationPoint < 0
  503. || this.animationPoint >= this.points.length
  504. || this.isDataLoad == false) {
  505. return;
  506. }
  507. var ctx = this.ctx,
  508. point = this.points[this.animationPoint],
  509. lastY = this.rectChartCenter.y - this.chartFontSize * 1.3,
  510. beginY = point.y,
  511. textY = (1 - v) * Math.abs(beginY - lastY) + lastY,
  512. beginAlpha = 0.4,
  513. endAlpha = 0.8,
  514. alpha = v * (endAlpha - beginAlpha) + beginAlpha;
  515. /* draw step number */
  516. ctx.save();
  517. ctx.font = 'bold ' + this.chartFontSize + "px " + this.fontFamily;
  518. ctx.textAlign = this.animationPoint == this.points.length - 1 ? 'right' : point.textAlign;
  519. ctx.fillStyle = "white";
  520. ctx.globalAlpha = alpha;
  521. ctx.fillText(point.value.toString(), point.x, textY);
  522. ctx.restore();
  523. },
  524. /* draw rank */
  525. drawRank: function () {
  526. if (this.rankRef == null) {
  527. return;
  528. }
  529. var ctx = this.ctx,
  530. padding = 20,
  531. imageRect = {
  532. x: this.rectRankAvatar.x + padding,
  533. y: this.rectRankAvatar.y + padding,
  534. width: this.rectRankAvatar.width - 2 * padding,
  535. height: this.rectRankAvatar.height - 2 * padding
  536. },
  537. imageRadius = imageRect.width / 2,
  538. rankRef = this.rankRef;
  539. /* draw a line */
  540. ctx.save();
  541. ctx.beginPath();
  542. ctx.moveTo(this.rectRank.x, this.rectRank.y);
  543. ctx.lineTo(this.rectRank.x + this.rectRank.width , this.rectRank.y);
  544. ctx.moveTo(this.rectRank.x, this.rectRank.y + this.rectRank.height);
  545. ctx.lineTo(this.rectRank.x + this.rectRank.width , this.rectRank.y + this.rectRank.height);
  546. ctx.fillStyle = "white";
  547. ctx.lineWidth = 1;
  548. ctx.globalAlpha = 0.8;
  549. ctx.stroke();
  550. ctx.restore();
  551. /* draw customer avatar image */
  552. ctx.save();
  553. ctx.beginPath();
  554. ctx.strokeStyle = "#ffffff";
  555. ctx.lineWidth = 2;
  556. ctx.globalAlpha = 0.5;
  557. ctx.arc(imageRect.x + imageRadius, imageRect.y + imageRadius, imageRadius, 0, 2 * Math.PI, true);
  558. ctx.stroke();
  559. ctx.restore();
  560. ctx.save();
  561. ctx.clip();
  562. ctx.globalAlpha = 1;
  563. ctx.drawImage(rankRef.avatar, imageRect.x, imageRect.y, imageRect.width, imageRect.height);
  564. ctx.restore();
  565. /* draw text */
  566. ctx.save();
  567. var fontSize = 36;
  568. ctx.font = fontSize + "px " + this.fontFamily;
  569. ctx.fillStyle = "white";
  570. ctx.globalAlpha = 0.5;
  571. ctx.fillText(this.rankRef.title, this.rectRankText.x + this.margin,
  572. this.rectRankText.y + (this.rectRankText.height + fontSize * 3 / 4) / 2,
  573. this.rectRankText.width);
  574. ctx.stroke();
  575. ctx.restore();
  576. /* draw a arrows button */
  577. ctx.save();
  578. var btnPadding = 50,
  579. btnSmall = {
  580. x: this.rectRankBtn.x + 1.6 * btnPadding,
  581. y: this.rectRankBtn.y + btnPadding,
  582. width: this.rectRankAvatar.width - 2 * btnPadding,
  583. height: this.rectRankAvatar.height - 2 * btnPadding
  584. };
  585. ctx.fillStyle = "white";
  586. ctx.beginPath();
  587. ctx.moveTo(btnSmall.x, btnSmall.y);
  588. ctx.lineTo(btnSmall.x + btnSmall.width / 2, btnSmall.y + btnSmall.height / 2);
  589. ctx.lineTo(btnSmall.x, btnSmall.y + btnSmall.height);
  590. ctx.lineWidth = 5;
  591. ctx.globalAlpha = 0.6;
  592. ctx.stroke();
  593. ctx.restore();
  594. },
  595. /**
  596. * Draw with animate
  597. * @param {number} v Value
  598. */
  599. drawAnimated: function (v) {
  600. var self = this,
  601. el = this.el;
  602. el.trigger('motion-animation-start');
  603. $(this.canvas)
  604. .stop(true, true)
  605. .css({animationProgress: 0})
  606. .animate({animationProgress: 1}, $.extend({}, this.animation, {
  607. step: function (animationProgress) {
  608. var stepValue = self.animationStartValue * (1 - animationProgress) + v * animationProgress;
  609. self.drawFrame(stepValue);
  610. el.trigger('motion-animation-step', [animationProgress, stepValue]);
  611. },
  612. complete: function () {
  613. el.trigger('motion-animation-end');
  614. }
  615. }));
  616. },
  617. /**
  618. * click function of this element
  619. * @param e event of click
  620. */
  621. clickFuc: function (e) {
  622. var dataName = 'motion';
  623. var el = $(this),
  624. instance = el.data(dataName),
  625. offset = el.offset(),
  626. point;
  627. if(e.type == "tap"){
  628. var touch = e.originalEvent.detail.touches[0];
  629. point = {x: touch.pageX - offset.left, y: touch.pageY - offset.top};
  630. }else{
  631. point = {x: e.pageX - offset.left, y: e.pageY - offset.top};
  632. }
  633. if (instance.isPointInRect(instance.rectChart, point)) {
  634. if (instance.isDataLoad) {
  635. /* click in chart */
  636. var points = instance.points;
  637. for(var i = 0; i < points.length; i++) {
  638. if (instance.isPointInRect(points[i].rect, point)) {
  639. instance.animationPoint = i;
  640. if (instance) {
  641. instance.draw();
  642. }
  643. break;
  644. }
  645. }
  646. }
  647. } else if (instance.isPointInRect(instance.rectRank, point)) {
  648. /* click in rank */
  649. if (instance.rankRef) {
  650. location.href = instance.rankRef.url;
  651. }
  652. }
  653. },
  654. /**
  655. * check point is in rect, return true when point in rect
  656. * @param rect Object {x, y, width, height}
  657. * @param point Object {x, y}
  658. */
  659. isPointInRect: function(rect, point) {
  660. return point.x >= rect.x && point.x <= rect.x + rect.width
  661. && point.y >= rect.y && point.y <= rect.y + rect.height;
  662. }
  663. };
  664. /*-------------------------------------------- Initiating jQuery plugin ------------------------------------------*/
  665. $.wcChart = {
  666. defaults: WcChart.prototype
  667. };
  668. /**
  669. * Add a customer easing, in effect, it is a easeOutCirc (see easing http://easings.net/zh-cn)
  670. */
  671. $.easing.wcChart = function (x, t, b, c, d) {
  672. return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  673. };
  674. /**
  675. * Draw animated circular progress bar.
  676. *
  677. * Appends <canvas> to the element or updates already appended one.
  678. *
  679. * If animated, throws 3 events:
  680. *
  681. * - motion-animation-start(jqEvent)
  682. * - motion-animation-step(jqEvent, animationProgress, stepValue) - multiple event;
  683. * animationProgress: from 0.0 to 1.0;
  684. * stepValue: from 0.0 to value
  685. * - motion-animation-end(jqEvent)
  686. *
  687. * @param config Example: { value: 0.75, width: 920, height: 600, animation: false };
  688. * you may set any of public options;
  689. * `animation` may be set to false;
  690. */
  691. $.fn.wcChart = function (config) {
  692. var dataName = 'motion';
  693. if (config == 'widget') {
  694. var data = this.data(dataName);
  695. return data && data.canvas;
  696. }
  697. var el = $(this),
  698. instance = el.data(dataName),
  699. cfg = $.isPlainObject(config) ? config : {};
  700. if (instance) {
  701. instance.init(cfg);
  702. } else {
  703. cfg.el = el;
  704. instance = new WcChart(cfg);
  705. el.data(dataName, instance);
  706. }
  707. return this;
  708. };
  709. /**
  710. * Add a round rect draw in the 2D context
  711. * @param x number, begin of x-axis
  712. * @param y number, begin of y-axis
  713. * @param width number,
  714. * @param height number
  715. * @param radius number, radius of quad curve
  716. * @param fill bool, fill
  717. * @param stroke bool, stroke
  718. */
  719. CanvasRenderingContext2D.prototype.roundRect = function (x, y, width, height, radius, fill, stroke) {
  720. stroke = typeof stroke == "undefined" ? true : stroke;
  721. stroke = typeof stroke == "undefined" ? true : stroke;
  722. radius = typeof radius == "undefined" ? 5 : radius;
  723. this.beginPath();
  724. this.moveTo(x + radius, y);
  725. this.lineTo(x + width - radius, y);
  726. this.quadraticCurveTo(x + width, y, x + width, y + radius);
  727. this.lineTo(x + width, y + height - radius);
  728. this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  729. this.lineTo(x + radius, y + height);
  730. this.quadraticCurveTo(x, y + height, x, y + height - radius);
  731. this.lineTo(x, y + radius);
  732. this.quadraticCurveTo(x, y, x + radius, y);
  733. this.closePath();
  734. if (stroke) {
  735. this.stroke();
  736. }
  737. if (fill) {
  738. this.fill();
  739. }
  740. };
  741. /**
  742. *
  743. * @param fromX number, x-axis
  744. * @param fromY number,
  745. * @param toX number,
  746. * @param toY number,
  747. * @param pattern deltay
  748. */
  749. CanvasRenderingContext2D.prototype.dashedLineTo = function (fromX, fromY, toX, toY, pattern) {
  750. var interval = 0, padding = 0;
  751. if (typeof pattern === "undefined") {
  752. padding = 5;
  753. interval = 5;
  754. } else {
  755. if (pattern.constructor === Array) {
  756. padding = pattern[0];
  757. interval = pattern[1];
  758. } else {
  759. padding = interval = pattern;
  760. }
  761. }
  762. /* calculate the delta x and delta y */
  763. var dx = (toX - fromX);
  764. var dy = (toY - fromY);
  765. var distance = Math.floor(Math.sqrt(dx * dx + dy * dy));
  766. var unitLength = padding + interval;
  767. var dashLineInterval = (unitLength <= 0) ? distance : Math.floor(distance / unitLength);
  768. var deltaPaddingY = (dy / distance) * padding;
  769. var deltaPaddingX = (dx / distance) * padding;
  770. var unitLengthX = (dx / distance) * unitLength;
  771. var unitLengthY = (dy / distance) * unitLength;
  772. /* draw dash line */
  773. var x = fromX, y = fromY;
  774. for (var dl = 0; dl < dashLineInterval; dl++) {
  775. this.moveTo(x, y);
  776. this.lineTo(x + deltaPaddingX, y + deltaPaddingY);
  777. x += unitLengthX;
  778. y += unitLengthY;
  779. }
  780. };
  781. })(jQuery);