gauge.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. // Generated by CoffeeScript 1.10.0
  2. (function() {
  3. var AnimatedText, AnimatedTextFactory, Bar, BaseDonut, BaseGauge, Donut, Gauge, GaugePointer, TextRenderer, ValueUpdater, addCommas, cutHex, formatNumber, mergeObjects, secondsToString,
  4. slice = [].slice,
  5. hasProp = {}.hasOwnProperty,
  6. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
  7. (function() {
  8. var browserRequestAnimationFrame, isCancelled, j, lastId, len, vendor, vendors;
  9. vendors = ['ms', 'moz', 'webkit', 'o'];
  10. for (j = 0, len = vendors.length; j < len; j++) {
  11. vendor = vendors[j];
  12. if (window.requestAnimationFrame) {
  13. break;
  14. }
  15. window.requestAnimationFrame = window[vendor + 'RequestAnimationFrame'];
  16. window.cancelAnimationFrame = window[vendor + 'CancelAnimationFrame'] || window[vendor + 'CancelRequestAnimationFrame'];
  17. }
  18. browserRequestAnimationFrame = null;
  19. lastId = 0;
  20. isCancelled = {};
  21. if (!requestAnimationFrame) {
  22. window.requestAnimationFrame = function(callback, element) {
  23. var currTime, id, lastTime, timeToCall;
  24. currTime = new Date().getTime();
  25. timeToCall = Math.max(0, 16 - (currTime - lastTime));
  26. id = window.setTimeout(function() {
  27. return callback(currTime + timeToCall);
  28. }, timeToCall);
  29. lastTime = currTime + timeToCall;
  30. return id;
  31. };
  32. return window.cancelAnimationFrame = function(id) {
  33. return clearTimeout(id);
  34. };
  35. } else if (!window.cancelAnimationFrame) {
  36. browserRequestAnimationFrame = window.requestAnimationFrame;
  37. window.requestAnimationFrame = function(callback, element) {
  38. var myId;
  39. myId = ++lastId;
  40. browserRequestAnimationFrame(function() {
  41. if (!isCancelled[myId]) {
  42. return callback();
  43. }
  44. }, element);
  45. return myId;
  46. };
  47. return window.cancelAnimationFrame = function(id) {
  48. return isCancelled[id] = true;
  49. };
  50. }
  51. })();
  52. secondsToString = function(sec) {
  53. var hr, min;
  54. hr = Math.floor(sec / 3600);
  55. min = Math.floor((sec - (hr * 3600)) / 60);
  56. sec -= (hr * 3600) + (min * 60);
  57. sec += '';
  58. min += '';
  59. while (min.length < 2) {
  60. min = '0' + min;
  61. }
  62. while (sec.length < 2) {
  63. sec = '0' + sec;
  64. }
  65. hr = hr ? hr + ':' : '';
  66. return hr + min + ':' + sec;
  67. };
  68. formatNumber = function() {
  69. var digits, num, value;
  70. num = 1 <= arguments.length ? slice.call(arguments, 0) : [];
  71. value = num[0];
  72. digits = 0 || num[1];
  73. return addCommas(value.toFixed(digits));
  74. };
  75. mergeObjects = function(obj1, obj2) {
  76. var key, out, val;
  77. out = {};
  78. for (key in obj1) {
  79. if (!hasProp.call(obj1, key)) continue;
  80. val = obj1[key];
  81. out[key] = val;
  82. }
  83. for (key in obj2) {
  84. if (!hasProp.call(obj2, key)) continue;
  85. val = obj2[key];
  86. out[key] = val;
  87. }
  88. return out;
  89. };
  90. addCommas = function(nStr) {
  91. var rgx, x, x1, x2;
  92. nStr += '';
  93. x = nStr.split('.');
  94. x1 = x[0];
  95. x2 = '';
  96. if (x.length > 1) {
  97. x2 = '.' + x[1];
  98. }
  99. rgx = /(\d+)(\d{3})/;
  100. while (rgx.test(x1)) {
  101. x1 = x1.replace(rgx, '$1' + ',' + '$2');
  102. }
  103. return x1 + x2;
  104. };
  105. cutHex = function(nStr) {
  106. if (nStr.charAt(0) === "#") {
  107. return nStr.substring(1, 7);
  108. }
  109. return nStr;
  110. };
  111. ValueUpdater = (function() {
  112. ValueUpdater.prototype.animationSpeed = 32;
  113. function ValueUpdater(addToAnimationQueue, clear) {
  114. if (addToAnimationQueue == null) {
  115. addToAnimationQueue = true;
  116. }
  117. this.clear = clear != null ? clear : true;
  118. if (addToAnimationQueue) {
  119. AnimationUpdater.add(this);
  120. }
  121. }
  122. ValueUpdater.prototype.update = function(force) {
  123. var diff;
  124. if (force == null) {
  125. force = false;
  126. }
  127. if (force || this.displayedValue !== this.value) {
  128. if (this.ctx && this.clear) {
  129. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  130. }
  131. diff = this.value - this.displayedValue;
  132. if (Math.abs(diff / this.animationSpeed) <= 0.001) {
  133. this.displayedValue = this.value;
  134. } else {
  135. this.displayedValue = this.displayedValue + diff / this.animationSpeed;
  136. }
  137. this.render();
  138. return true;
  139. }
  140. return false;
  141. };
  142. return ValueUpdater;
  143. })();
  144. BaseGauge = (function(superClass) {
  145. extend(BaseGauge, superClass);
  146. function BaseGauge() {
  147. return BaseGauge.__super__.constructor.apply(this, arguments);
  148. }
  149. BaseGauge.prototype.displayScale = 1;
  150. BaseGauge.prototype.forceUpdate = true;
  151. BaseGauge.prototype.setTextField = function(textField, fractionDigits) {
  152. return this.textField = textField instanceof TextRenderer ? textField : new TextRenderer(textField, fractionDigits);
  153. };
  154. BaseGauge.prototype.setMinValue = function(minValue, updateStartValue) {
  155. var gauge, j, len, ref, results;
  156. this.minValue = minValue;
  157. if (updateStartValue == null) {
  158. updateStartValue = true;
  159. }
  160. if (updateStartValue) {
  161. this.displayedValue = this.minValue;
  162. ref = this.gp || [];
  163. results = [];
  164. for (j = 0, len = ref.length; j < len; j++) {
  165. gauge = ref[j];
  166. results.push(gauge.displayedValue = this.minValue);
  167. }
  168. return results;
  169. }
  170. };
  171. BaseGauge.prototype.setOptions = function(options) {
  172. if (options == null) {
  173. options = null;
  174. }
  175. this.options = mergeObjects(this.options, options);
  176. if (this.textField) {
  177. this.textField.el.style.fontSize = options.fontSize + 'px';
  178. }
  179. if (this.options.angle > .5) {
  180. this.options.angle = .5;
  181. }
  182. this.configDisplayScale();
  183. return this;
  184. };
  185. BaseGauge.prototype.configDisplayScale = function() {
  186. var backingStorePixelRatio, devicePixelRatio, height, prevDisplayScale, width;
  187. prevDisplayScale = this.displayScale;
  188. if (this.options.highDpiSupport === false) {
  189. delete this.displayScale;
  190. } else {
  191. devicePixelRatio = window.devicePixelRatio || 1;
  192. backingStorePixelRatio = this.ctx.webkitBackingStorePixelRatio || this.ctx.mozBackingStorePixelRatio || this.ctx.msBackingStorePixelRatio || this.ctx.oBackingStorePixelRatio || this.ctx.backingStorePixelRatio || 1;
  193. this.displayScale = devicePixelRatio / backingStorePixelRatio;
  194. }
  195. if (this.displayScale !== prevDisplayScale) {
  196. width = this.canvas.G__width || this.canvas.width;
  197. height = this.canvas.G__height || this.canvas.height;
  198. this.canvas.width = width * this.displayScale;
  199. this.canvas.height = height * this.displayScale;
  200. this.canvas.style.width = width + "px";
  201. this.canvas.style.height = height + "px";
  202. this.canvas.G__width = width;
  203. this.canvas.G__height = height;
  204. }
  205. return this;
  206. };
  207. BaseGauge.prototype.parseValue = function(value) {
  208. value = parseFloat(value) || Number(value);
  209. if (isFinite(value)) {
  210. return value;
  211. } else {
  212. return 0;
  213. }
  214. };
  215. return BaseGauge;
  216. })(ValueUpdater);
  217. TextRenderer = (function() {
  218. function TextRenderer(el, fractionDigits1) {
  219. this.el = el;
  220. this.fractionDigits = fractionDigits1;
  221. }
  222. TextRenderer.prototype.render = function(gauge) {
  223. return this.el.innerHTML = formatNumber(gauge.displayedValue, this.fractionDigits);
  224. };
  225. return TextRenderer;
  226. })();
  227. AnimatedText = (function(superClass) {
  228. extend(AnimatedText, superClass);
  229. AnimatedText.prototype.displayedValue = 0;
  230. AnimatedText.prototype.value = 0;
  231. AnimatedText.prototype.setVal = function(value) {
  232. return this.value = 1 * value;
  233. };
  234. function AnimatedText(elem1, text) {
  235. this.elem = elem1;
  236. this.text = text != null ? text : false;
  237. AnimatedText.__super__.constructor.call(this);
  238. if (this.elem === void 0) {
  239. throw new Error('The element isn\'t defined.');
  240. }
  241. this.value = 1 * this.elem.innerHTML;
  242. if (this.text) {
  243. this.value = 0;
  244. }
  245. }
  246. AnimatedText.prototype.render = function() {
  247. var textVal;
  248. if (this.text) {
  249. textVal = secondsToString(this.displayedValue.toFixed(0));
  250. } else {
  251. textVal = addCommas(formatNumber(this.displayedValue));
  252. }
  253. return this.elem.innerHTML = textVal;
  254. };
  255. return AnimatedText;
  256. })(ValueUpdater);
  257. AnimatedTextFactory = {
  258. create: function(objList) {
  259. var elem, j, len, out;
  260. out = [];
  261. for (j = 0, len = objList.length; j < len; j++) {
  262. elem = objList[j];
  263. out.push(new AnimatedText(elem));
  264. }
  265. return out;
  266. }
  267. };
  268. GaugePointer = (function(superClass) {
  269. extend(GaugePointer, superClass);
  270. GaugePointer.prototype.displayedValue = 0;
  271. GaugePointer.prototype.value = 0;
  272. GaugePointer.prototype.options = {
  273. strokeWidth: 0.035,
  274. length: 0.1,
  275. color: "#000000",
  276. iconPath: null,
  277. iconScale: 1.0,
  278. iconAngle: 0
  279. };
  280. GaugePointer.prototype.img = null;
  281. function GaugePointer(gauge1) {
  282. this.gauge = gauge1;
  283. if (this.gauge === void 0) {
  284. throw new Error('The element isn\'t defined.');
  285. }
  286. this.ctx = this.gauge.ctx;
  287. this.canvas = this.gauge.canvas;
  288. GaugePointer.__super__.constructor.call(this, false, false);
  289. this.setOptions();
  290. }
  291. GaugePointer.prototype.setOptions = function(options) {
  292. if (options == null) {
  293. options = null;
  294. }
  295. this.options = mergeObjects(this.options, options);
  296. this.length = 2 * this.gauge.radius * this.gauge.options.radiusScale * this.options.length;
  297. this.strokeWidth = this.canvas.height * this.options.strokeWidth;
  298. this.maxValue = this.gauge.maxValue;
  299. this.minValue = this.gauge.minValue;
  300. this.animationSpeed = this.gauge.animationSpeed;
  301. this.options.angle = this.gauge.options.angle;
  302. if (this.options.iconPath) {
  303. this.img = new Image();
  304. return this.img.src = this.options.iconPath;
  305. }
  306. };
  307. GaugePointer.prototype.render = function() {
  308. var angle, endX, endY, imgX, imgY, startX, startY, x, y;
  309. angle = this.gauge.getAngle.call(this, this.displayedValue);
  310. x = Math.round(this.length * Math.cos(angle));
  311. y = Math.round(this.length * Math.sin(angle));
  312. startX = Math.round(this.strokeWidth * Math.cos(angle - Math.PI / 2));
  313. startY = Math.round(this.strokeWidth * Math.sin(angle - Math.PI / 2));
  314. endX = Math.round(this.strokeWidth * Math.cos(angle + Math.PI / 2));
  315. endY = Math.round(this.strokeWidth * Math.sin(angle + Math.PI / 2));
  316. this.ctx.beginPath();
  317. this.ctx.fillStyle = this.options.color;
  318. this.ctx.arc(0, 0, this.strokeWidth, 0, Math.PI * 2, false);
  319. this.ctx.fill();
  320. this.ctx.beginPath();
  321. this.ctx.moveTo(startX, startY);
  322. this.ctx.lineTo(x, y);
  323. this.ctx.lineTo(endX, endY);
  324. this.ctx.fill();
  325. if (this.img) {
  326. imgX = Math.round(this.img.width * this.options.iconScale);
  327. imgY = Math.round(this.img.height * this.options.iconScale);
  328. this.ctx.save();
  329. this.ctx.translate(x, y);
  330. this.ctx.rotate(angle + Math.PI / 180.0 * (90 + this.options.iconAngle));
  331. this.ctx.drawImage(this.img, -imgX / 2, -imgY / 2, imgX, imgY);
  332. return this.ctx.restore();
  333. }
  334. };
  335. return GaugePointer;
  336. })(ValueUpdater);
  337. Bar = (function() {
  338. function Bar(elem1) {
  339. this.elem = elem1;
  340. }
  341. Bar.prototype.updateValues = function(arrValues) {
  342. this.value = arrValues[0];
  343. this.maxValue = arrValues[1];
  344. this.avgValue = arrValues[2];
  345. return this.render();
  346. };
  347. Bar.prototype.render = function() {
  348. var avgPercent, valPercent;
  349. if (this.textField) {
  350. this.textField.text(formatNumber(this.value));
  351. }
  352. if (this.maxValue === 0) {
  353. this.maxValue = this.avgValue * 2;
  354. }
  355. valPercent = (this.value / this.maxValue) * 100;
  356. avgPercent = (this.avgValue / this.maxValue) * 100;
  357. $(".bar-value", this.elem).css({
  358. "width": valPercent + "%"
  359. });
  360. return $(".typical-value", this.elem).css({
  361. "width": avgPercent + "%"
  362. });
  363. };
  364. return Bar;
  365. })();
  366. Gauge = (function(superClass) {
  367. extend(Gauge, superClass);
  368. Gauge.prototype.elem = null;
  369. Gauge.prototype.value = [20];
  370. Gauge.prototype.maxValue = 80;
  371. Gauge.prototype.minValue = 0;
  372. Gauge.prototype.displayedAngle = 0;
  373. Gauge.prototype.displayedValue = 0;
  374. Gauge.prototype.lineWidth = 40;
  375. Gauge.prototype.paddingTop = 0.1;
  376. Gauge.prototype.paddingBottom = 0.1;
  377. Gauge.prototype.percentColors = null;
  378. Gauge.prototype.options = {
  379. colorStart: "#6fadcf",
  380. colorStop: void 0,
  381. gradientType: 0,
  382. strokeColor: "#e0e0e0",
  383. pointer: {
  384. length: 0.8,
  385. strokeWidth: 0.035,
  386. iconScale: 1.0
  387. },
  388. angle: 0.15,
  389. lineWidth: 0.44,
  390. radiusScale: 1.0,
  391. fontSize: 40,
  392. limitMax: false,
  393. limitMin: false
  394. };
  395. function Gauge(canvas) {
  396. var h, w;
  397. this.canvas = canvas;
  398. Gauge.__super__.constructor.call(this);
  399. this.percentColors = null;
  400. if (typeof G_vmlCanvasManager !== 'undefined') {
  401. this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
  402. }
  403. this.ctx = this.canvas.getContext('2d');
  404. h = this.canvas.clientHeight;
  405. w = this.canvas.clientWidth;
  406. this.canvas.height = h;
  407. this.canvas.width = w;
  408. this.gp = [new GaugePointer(this)];
  409. this.setOptions();
  410. }
  411. Gauge.prototype.setOptions = function(options) {
  412. var gauge, j, len, phi, ref;
  413. if (options == null) {
  414. options = null;
  415. }
  416. Gauge.__super__.setOptions.call(this, options);
  417. this.configPercentColors();
  418. this.extraPadding = 0;
  419. if (this.options.angle < 0) {
  420. phi = Math.PI * (1 + this.options.angle);
  421. this.extraPadding = Math.sin(phi);
  422. }
  423. this.availableHeight = this.canvas.height * (1 - this.paddingTop - this.paddingBottom);
  424. this.lineWidth = this.availableHeight * this.options.lineWidth;
  425. this.radius = (this.availableHeight - this.lineWidth / 2) / (1.0 + this.extraPadding);
  426. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  427. ref = this.gp;
  428. for (j = 0, len = ref.length; j < len; j++) {
  429. gauge = ref[j];
  430. gauge.setOptions(this.options.pointer);
  431. gauge.render();
  432. }
  433. this.render();
  434. return this;
  435. };
  436. Gauge.prototype.configPercentColors = function() {
  437. var bval, gval, i, j, ref, results, rval;
  438. this.percentColors = null;
  439. if (this.options.percentColors !== void 0) {
  440. this.percentColors = new Array();
  441. results = [];
  442. for (i = j = 0, ref = this.options.percentColors.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
  443. rval = parseInt((cutHex(this.options.percentColors[i][1])).substring(0, 2), 16);
  444. gval = parseInt((cutHex(this.options.percentColors[i][1])).substring(2, 4), 16);
  445. bval = parseInt((cutHex(this.options.percentColors[i][1])).substring(4, 6), 16);
  446. results.push(this.percentColors[i] = {
  447. pct: this.options.percentColors[i][0],
  448. color: {
  449. r: rval,
  450. g: gval,
  451. b: bval
  452. }
  453. });
  454. }
  455. return results;
  456. }
  457. };
  458. Gauge.prototype.set = function(value) {
  459. var gp, i, j, k, l, len, ref, ref1, val;
  460. if (!(value instanceof Array)) {
  461. value = [value];
  462. }
  463. for (i = j = 0, ref = value.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
  464. value[i] = this.parseValue(value[i]);
  465. }
  466. if (value.length > this.gp.length) {
  467. for (i = k = 0, ref1 = value.length - this.gp.length; 0 <= ref1 ? k < ref1 : k > ref1; i = 0 <= ref1 ? ++k : --k) {
  468. gp = new GaugePointer(this);
  469. gp.setOptions(this.options.pointer);
  470. this.gp.push(gp);
  471. }
  472. } else if (value.length < this.gp.length) {
  473. this.gp = this.gp.slice(this.gp.length - value.length);
  474. }
  475. i = 0;
  476. for (l = 0, len = value.length; l < len; l++) {
  477. val = value[l];
  478. if (val > this.maxValue) {
  479. if (this.options.limitMax) {
  480. val = this.maxValue;
  481. } else {
  482. this.maxValue = val + 1;
  483. }
  484. } else if (val < this.minValue) {
  485. if (this.options.limitMin) {
  486. val = this.minValue;
  487. } else {
  488. this.minValue = val - 1;
  489. }
  490. }
  491. this.gp[i].value = val;
  492. this.gp[i++].setOptions({
  493. minValue: this.minValue,
  494. maxValue: this.maxValue,
  495. angle: this.options.angle
  496. });
  497. }
  498. this.value = Math.max(Math.min(value[value.length - 1], this.maxValue), this.minValue);
  499. AnimationUpdater.run(this.forceUpdate);
  500. return this.forceUpdate = false;
  501. };
  502. Gauge.prototype.getAngle = function(value) {
  503. return (1 + this.options.angle) * Math.PI + ((value - this.minValue) / (this.maxValue - this.minValue)) * (1 - this.options.angle * 2) * Math.PI;
  504. };
  505. Gauge.prototype.getColorForPercentage = function(pct, grad) {
  506. var color, endColor, i, j, rangePct, ref, startColor;
  507. if (pct === 0) {
  508. color = this.percentColors[0].color;
  509. } else {
  510. color = this.percentColors[this.percentColors.length - 1].color;
  511. for (i = j = 0, ref = this.percentColors.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
  512. if (pct <= this.percentColors[i].pct) {
  513. if (grad === true) {
  514. startColor = this.percentColors[i - 1] || this.percentColors[0];
  515. endColor = this.percentColors[i];
  516. rangePct = (pct - startColor.pct) / (endColor.pct - startColor.pct);
  517. color = {
  518. r: Math.floor(startColor.color.r * (1 - rangePct) + endColor.color.r * rangePct),
  519. g: Math.floor(startColor.color.g * (1 - rangePct) + endColor.color.g * rangePct),
  520. b: Math.floor(startColor.color.b * (1 - rangePct) + endColor.color.b * rangePct)
  521. };
  522. } else {
  523. color = this.percentColors[i].color;
  524. }
  525. break;
  526. }
  527. }
  528. }
  529. return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';
  530. };
  531. Gauge.prototype.getColorForValue = function(val, grad) {
  532. var pct;
  533. pct = (val - this.minValue) / (this.maxValue - this.minValue);
  534. return this.getColorForPercentage(pct, grad);
  535. };
  536. Gauge.prototype.renderStaticLabels = function(staticLabels, w, h, radius) {
  537. var font, fontsize, j, len, match, re, ref, rest, rotationAngle, value;
  538. this.ctx.save();
  539. this.ctx.translate(w, h);
  540. font = staticLabels.font || "10px Times";
  541. re = /\d+\.?\d?/;
  542. match = font.match(re)[0];
  543. rest = font.slice(match.length);
  544. fontsize = parseFloat(match) * this.displayScale;
  545. this.ctx.font = fontsize + rest;
  546. this.ctx.fillStyle = staticLabels.color || "#000000";
  547. this.ctx.textBaseline = "bottom";
  548. this.ctx.textAlign = "center";
  549. ref = staticLabels.labels;
  550. for (j = 0, len = ref.length; j < len; j++) {
  551. value = ref[j];
  552. if (value.label !== void 0) {
  553. if ((!this.options.limitMin || value >= this.minValue) && (!this.options.limitMax || value <= this.maxValue)) {
  554. font = value.font || staticLabels.font;
  555. match = font.match(re)[0];
  556. rest = font.slice(match.length);
  557. fontsize = parseFloat(match) * this.displayScale;
  558. this.ctx.font = fontsize + rest;
  559. rotationAngle = this.getAngle(value.label) - 3 * Math.PI / 2;
  560. this.ctx.rotate(rotationAngle);
  561. this.ctx.fillText(formatNumber(value.label, staticLabels.fractionDigits), 0, -radius - this.lineWidth / 2);
  562. this.ctx.rotate(-rotationAngle);
  563. }
  564. } else {
  565. if ((!this.options.limitMin || value >= this.minValue) && (!this.options.limitMax || value <= this.maxValue)) {
  566. rotationAngle = this.getAngle(value) - 3 * Math.PI / 2;
  567. this.ctx.rotate(rotationAngle);
  568. this.ctx.fillText(formatNumber(value, staticLabels.fractionDigits), 0, -radius - this.lineWidth / 2);
  569. this.ctx.rotate(-rotationAngle);
  570. }
  571. }
  572. }
  573. return this.ctx.restore();
  574. };
  575. Gauge.prototype.renderTicks = function(ticksOptions, w, h, radius) {
  576. var currentDivision, currentSubDivision, divColor, divLength, divWidth, divisionCount, j, lineWidth, range, rangeDivisions, ref, results, scaleMutate, st, subColor, subDivisions, subLength, subWidth, subdivisionCount, t, tmpRadius;
  577. if (ticksOptions !== {}) {
  578. divisionCount = ticksOptions.divisions || 0;
  579. subdivisionCount = ticksOptions.subDivisions || 0;
  580. divColor = ticksOptions.divColor || '#fff';
  581. subColor = ticksOptions.subColor || '#fff';
  582. divLength = ticksOptions.divLength || 0.7;
  583. subLength = ticksOptions.subLength || 0.2;
  584. range = parseFloat(this.maxValue) - parseFloat(this.minValue);
  585. rangeDivisions = parseFloat(range) / parseFloat(ticksOptions.divisions);
  586. subDivisions = parseFloat(rangeDivisions) / parseFloat(ticksOptions.subDivisions);
  587. currentDivision = parseFloat(this.minValue);
  588. currentSubDivision = 0.0 + subDivisions;
  589. lineWidth = range / 400;
  590. divWidth = lineWidth * (ticksOptions.divWidth || 1);
  591. subWidth = lineWidth * (ticksOptions.subWidth || 1);
  592. results = [];
  593. for (t = j = 0, ref = divisionCount + 1; j < ref; t = j += 1) {
  594. this.ctx.lineWidth = this.lineWidth * divLength;
  595. scaleMutate = (this.lineWidth / 2) * (1 - divLength);
  596. tmpRadius = (this.radius * this.options.radiusScale) + scaleMutate;
  597. this.ctx.strokeStyle = divColor;
  598. this.ctx.beginPath();
  599. this.ctx.arc(0, 0, tmpRadius, this.getAngle(currentDivision - divWidth), this.getAngle(currentDivision + divWidth), false);
  600. this.ctx.stroke();
  601. currentSubDivision = currentDivision + subDivisions;
  602. currentDivision += rangeDivisions;
  603. if (t !== ticksOptions.divisions && subdivisionCount > 0) {
  604. results.push((function() {
  605. var k, ref1, results1;
  606. results1 = [];
  607. for (st = k = 0, ref1 = subdivisionCount - 1; k < ref1; st = k += 1) {
  608. this.ctx.lineWidth = this.lineWidth * subLength;
  609. scaleMutate = (this.lineWidth / 2) * (1 - subLength);
  610. tmpRadius = (this.radius * this.options.radiusScale) + scaleMutate;
  611. this.ctx.strokeStyle = subColor;
  612. this.ctx.beginPath();
  613. this.ctx.arc(0, 0, tmpRadius, this.getAngle(currentSubDivision - subWidth), this.getAngle(currentSubDivision + subWidth), false);
  614. this.ctx.stroke();
  615. results1.push(currentSubDivision += subDivisions);
  616. }
  617. return results1;
  618. }).call(this));
  619. } else {
  620. results.push(void 0);
  621. }
  622. }
  623. return results;
  624. }
  625. };
  626. Gauge.prototype.render = function() {
  627. var displayedAngle, fillStyle, gauge, h, j, k, len, len1, max, min, radius, ref, ref1, scaleMutate, tmpRadius, w, zone;
  628. w = this.canvas.width / 2;
  629. h = (this.canvas.height * this.paddingTop + this.availableHeight) - ((this.radius + this.lineWidth / 2) * this.extraPadding);
  630. displayedAngle = this.getAngle(this.displayedValue);
  631. if (this.textField) {
  632. this.textField.render(this);
  633. }
  634. this.ctx.lineCap = "butt";
  635. radius = this.radius * this.options.radiusScale;
  636. if (this.options.staticLabels) {
  637. this.renderStaticLabels(this.options.staticLabels, w, h, radius);
  638. }
  639. if (this.options.staticZones) {
  640. this.ctx.save();
  641. this.ctx.translate(w, h);
  642. this.ctx.lineWidth = this.lineWidth;
  643. ref = this.options.staticZones;
  644. for (j = 0, len = ref.length; j < len; j++) {
  645. zone = ref[j];
  646. min = zone.min;
  647. if (this.options.limitMin && min < this.minValue) {
  648. min = this.minValue;
  649. }
  650. max = zone.max;
  651. if (this.options.limitMax && max > this.maxValue) {
  652. max = this.maxValue;
  653. }
  654. tmpRadius = this.radius * this.options.radiusScale;
  655. if (zone.height) {
  656. this.ctx.lineWidth = this.lineWidth * zone.height;
  657. scaleMutate = (this.lineWidth / 2) * (zone.offset || 1 - zone.height);
  658. tmpRadius = (this.radius * this.options.radiusScale) + scaleMutate;
  659. }
  660. this.ctx.strokeStyle = zone.strokeStyle;
  661. this.ctx.beginPath();
  662. this.ctx.arc(0, 0, tmpRadius, this.getAngle(min), this.getAngle(max), false);
  663. this.ctx.stroke();
  664. }
  665. } else {
  666. if (this.options.customFillStyle !== void 0) {
  667. fillStyle = this.options.customFillStyle(this);
  668. } else if (this.percentColors !== null) {
  669. fillStyle = this.getColorForValue(this.displayedValue, this.options.generateGradient);
  670. } else if (this.options.colorStop !== void 0) {
  671. if (this.options.gradientType === 0) {
  672. fillStyle = this.ctx.createRadialGradient(w, h, 9, w, h, 70);
  673. } else {
  674. fillStyle = this.ctx.createLinearGradient(0, 0, w, 0);
  675. }
  676. fillStyle.addColorStop(0, this.options.colorStart);
  677. fillStyle.addColorStop(1, this.options.colorStop);
  678. } else {
  679. fillStyle = this.options.colorStart;
  680. }
  681. this.ctx.strokeStyle = fillStyle;
  682. this.ctx.beginPath();
  683. this.ctx.arc(w, h, radius, (1 + this.options.angle) * Math.PI, displayedAngle, false);
  684. this.ctx.lineWidth = this.lineWidth;
  685. this.ctx.stroke();
  686. this.ctx.strokeStyle = this.options.strokeColor;
  687. this.ctx.beginPath();
  688. this.ctx.arc(w, h, radius, displayedAngle, (2 - this.options.angle) * Math.PI, false);
  689. this.ctx.stroke();
  690. this.ctx.save();
  691. this.ctx.translate(w, h);
  692. }
  693. if (this.options.renderTicks) {
  694. this.renderTicks(this.options.renderTicks, w, h, radius);
  695. }
  696. this.ctx.restore();
  697. this.ctx.translate(w, h);
  698. ref1 = this.gp;
  699. for (k = 0, len1 = ref1.length; k < len1; k++) {
  700. gauge = ref1[k];
  701. gauge.update(true);
  702. }
  703. return this.ctx.translate(-w, -h);
  704. };
  705. return Gauge;
  706. })(BaseGauge);
  707. BaseDonut = (function(superClass) {
  708. extend(BaseDonut, superClass);
  709. BaseDonut.prototype.lineWidth = 15;
  710. BaseDonut.prototype.displayedValue = 0;
  711. BaseDonut.prototype.value = 33;
  712. BaseDonut.prototype.maxValue = 80;
  713. BaseDonut.prototype.minValue = 0;
  714. BaseDonut.prototype.options = {
  715. lineWidth: 0.10,
  716. colorStart: "#6f6ea0",
  717. colorStop: "#c0c0db",
  718. strokeColor: "#eeeeee",
  719. shadowColor: "#d5d5d5",
  720. angle: 0.35,
  721. radiusScale: 1.0
  722. };
  723. function BaseDonut(canvas) {
  724. this.canvas = canvas;
  725. BaseDonut.__super__.constructor.call(this);
  726. if (typeof G_vmlCanvasManager !== 'undefined') {
  727. this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
  728. }
  729. this.ctx = this.canvas.getContext('2d');
  730. this.setOptions();
  731. this.render();
  732. }
  733. BaseDonut.prototype.getAngle = function(value) {
  734. return (1 - this.options.angle) * Math.PI + ((value - this.minValue) / (this.maxValue - this.minValue)) * ((2 + this.options.angle) - (1 - this.options.angle)) * Math.PI;
  735. };
  736. BaseDonut.prototype.setOptions = function(options) {
  737. if (options == null) {
  738. options = null;
  739. }
  740. BaseDonut.__super__.setOptions.call(this, options);
  741. this.lineWidth = this.canvas.height * this.options.lineWidth;
  742. this.radius = this.options.radiusScale * (this.canvas.height / 2 - this.lineWidth / 2);
  743. return this;
  744. };
  745. BaseDonut.prototype.set = function(value) {
  746. this.value = this.parseValue(value);
  747. if (this.value > this.maxValue) {
  748. if (this.options.limitMax) {
  749. this.value = this.maxValue;
  750. } else {
  751. this.maxValue = this.value;
  752. }
  753. } else if (this.value < this.minValue) {
  754. if (this.options.limitMin) {
  755. this.value = this.minValue;
  756. } else {
  757. this.minValue = this.value;
  758. }
  759. }
  760. AnimationUpdater.run(this.forceUpdate);
  761. return this.forceUpdate = false;
  762. };
  763. BaseDonut.prototype.render = function() {
  764. var displayedAngle, grdFill, h, start, stop, w;
  765. displayedAngle = this.getAngle(this.displayedValue);
  766. w = this.canvas.width / 2;
  767. h = this.canvas.height / 2;
  768. if (this.textField) {
  769. this.textField.render(this);
  770. }
  771. grdFill = this.ctx.createRadialGradient(w, h, 39, w, h, 70);
  772. grdFill.addColorStop(0, this.options.colorStart);
  773. grdFill.addColorStop(1, this.options.colorStop);
  774. start = this.radius - this.lineWidth / 2;
  775. stop = this.radius + this.lineWidth / 2;
  776. this.ctx.strokeStyle = this.options.strokeColor;
  777. this.ctx.beginPath();
  778. this.ctx.arc(w, h, this.radius, (1 - this.options.angle) * Math.PI, (2 + this.options.angle) * Math.PI, false);
  779. this.ctx.lineWidth = this.lineWidth;
  780. this.ctx.lineCap = "round";
  781. this.ctx.stroke();
  782. this.ctx.strokeStyle = grdFill;
  783. this.ctx.beginPath();
  784. this.ctx.arc(w, h, this.radius, (1 - this.options.angle) * Math.PI, displayedAngle, false);
  785. return this.ctx.stroke();
  786. };
  787. return BaseDonut;
  788. })(BaseGauge);
  789. Donut = (function(superClass) {
  790. extend(Donut, superClass);
  791. function Donut() {
  792. return Donut.__super__.constructor.apply(this, arguments);
  793. }
  794. Donut.prototype.strokeGradient = function(w, h, start, stop) {
  795. var grd;
  796. grd = this.ctx.createRadialGradient(w, h, start, w, h, stop);
  797. grd.addColorStop(0, this.options.shadowColor);
  798. grd.addColorStop(0.12, this.options._orgStrokeColor);
  799. grd.addColorStop(0.88, this.options._orgStrokeColor);
  800. grd.addColorStop(1, this.options.shadowColor);
  801. return grd;
  802. };
  803. Donut.prototype.setOptions = function(options) {
  804. var h, start, stop, w;
  805. if (options == null) {
  806. options = null;
  807. }
  808. Donut.__super__.setOptions.call(this, options);
  809. w = this.canvas.width / 2;
  810. h = this.canvas.height / 2;
  811. start = this.radius - this.lineWidth / 2;
  812. stop = this.radius + this.lineWidth / 2;
  813. this.options._orgStrokeColor = this.options.strokeColor;
  814. this.options.strokeColor = this.strokeGradient(w, h, start, stop);
  815. return this;
  816. };
  817. return Donut;
  818. })(BaseDonut);
  819. window.AnimationUpdater = {
  820. elements: [],
  821. animId: null,
  822. addAll: function(list) {
  823. var elem, j, len, results;
  824. results = [];
  825. for (j = 0, len = list.length; j < len; j++) {
  826. elem = list[j];
  827. results.push(AnimationUpdater.elements.push(elem));
  828. }
  829. return results;
  830. },
  831. add: function(object) {
  832. return AnimationUpdater.elements.push(object);
  833. },
  834. run: function(force) {
  835. var elem, finished, isCallback, j, len, ref;
  836. if (force == null) {
  837. force = false;
  838. }
  839. isCallback = isFinite(parseFloat(force));
  840. if (isCallback || force === true) {
  841. finished = true;
  842. ref = AnimationUpdater.elements;
  843. for (j = 0, len = ref.length; j < len; j++) {
  844. elem = ref[j];
  845. if (elem.update(force === true)) {
  846. finished = false;
  847. }
  848. }
  849. return AnimationUpdater.animId = finished ? null : requestAnimationFrame(AnimationUpdater.run);
  850. } else if (force === false) {
  851. if (AnimationUpdater.animId === !null) {
  852. cancelAnimationFrame(AnimationUpdater.animId);
  853. }
  854. return AnimationUpdater.animId = requestAnimationFrame(AnimationUpdater.run);
  855. }
  856. }
  857. };
  858. if (typeof window.define === 'function' && (window.define.amd != null)) {
  859. define(function() {
  860. return {
  861. Gauge: Gauge,
  862. Donut: Donut,
  863. BaseDonut: BaseDonut,
  864. TextRenderer: TextRenderer
  865. };
  866. });
  867. } else if (typeof module !== 'undefined' && (module.exports != null)) {
  868. module.exports = {
  869. Gauge: Gauge,
  870. Donut: Donut,
  871. BaseDonut: BaseDonut,
  872. TextRenderer: TextRenderer
  873. };
  874. } else {
  875. window.Gauge = Gauge;
  876. window.Donut = Donut;
  877. window.BaseDonut = BaseDonut;
  878. window.TextRenderer = TextRenderer;
  879. }
  880. }).call(this);