Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

352 lignes
8.1 KiB

  1. import { makeSVGGroup } from '../utils/draw';
  2. import { xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, getPaths } from '../utils/draw';
  3. import { equilizeNoOfElements } from '../utils/draw-utils';
  4. import { translateHoriLine, translateVertLine, animateRegion, animateBar, animateDot, animatePath } from '../utils/animate';
  5. class ChartComponent {
  6. constructor({
  7. layerClass = '',
  8. layerTransform = '',
  9. constants,
  10. getData,
  11. makeElements,
  12. animateElements
  13. }) {
  14. this.layerTransform = layerTransform;
  15. this.constants = constants;
  16. this.makeElements = makeElements;
  17. this.getData = getData;
  18. this.animateElements = animateElements;
  19. this.store = [];
  20. this.layerClass = layerClass;
  21. this.layerClass = typeof(this.layerClass) === 'function'
  22. ? this.layerClass() : this.layerClass;
  23. this.refresh();
  24. }
  25. refresh(data) {
  26. this.data = data || this.getData();
  27. }
  28. setup(parent) {
  29. this.layer = makeSVGGroup(parent, this.layerClass, this.layerTransform);
  30. }
  31. make() {
  32. this.render(this.data);
  33. this.oldData = this.data;
  34. }
  35. render(data) {
  36. this.store = this.makeElements(data);
  37. this.layer.textContent = '';
  38. this.store.forEach(element => {
  39. this.layer.appendChild(element);
  40. });
  41. }
  42. update(animate = true) {
  43. this.refresh();
  44. let animateElements = []
  45. if(animate) {
  46. animateElements = this.animateElements(this.data);
  47. }
  48. return animateElements;
  49. }
  50. }
  51. let componentConfigs = {
  52. yAxis: {
  53. layerClass: 'y axis',
  54. makeElements(data) {
  55. return data.positions.map((position, i) =>
  56. yLine(position, data.labels[i], this.constants.width,
  57. {mode: this.constants.mode, pos: this.constants.pos})
  58. );
  59. },
  60. animateElements(newData) {
  61. let newPos = newData.positions;
  62. let newLabels = newData.labels;
  63. let oldPos = this.oldData.positions;
  64. let oldLabels = this.oldData.labels;
  65. [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);
  66. [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
  67. this.render({
  68. positions: oldPos,
  69. labels: newLabels
  70. });
  71. return this.store.map((line, i) => {
  72. return translateHoriLine(
  73. line, newPos[i], oldPos[i]
  74. );
  75. });
  76. }
  77. },
  78. xAxis: {
  79. layerClass: 'x axis',
  80. makeElements(data) {
  81. return data.positions.map((position, i) =>
  82. xLine(position, data.labels[i], this.constants.height,
  83. {mode: this.constants.mode, pos: this.constants.pos})
  84. );
  85. },
  86. animateElements(newData) {
  87. let newPos = newData.positions;
  88. let newLabels = newData.labels;
  89. let oldPos = this.oldData.positions;
  90. let oldLabels = this.oldData.labels;
  91. [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);
  92. [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
  93. this.render({
  94. positions: oldPos,
  95. labels: newLabels
  96. });
  97. return this.store.map((line, i) => {
  98. return translateVertLine(
  99. line, newPos[i], oldPos[i]
  100. );
  101. });
  102. }
  103. },
  104. yMarkers: {
  105. layerClass: 'y-markers',
  106. makeElements(data) {
  107. return data.map(marker =>
  108. yMarker(marker.position, marker.label, this.constants.width,
  109. {pos:'right', mode: 'span', lineType: 'dashed'})
  110. );
  111. },
  112. animateElements(newData) {
  113. [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);
  114. let newPos = newData.map(d => d.position);
  115. let newLabels = newData.map(d => d.label);
  116. let oldPos = this.oldData.map(d => d.position);
  117. let oldLabels = this.oldData.map(d => d.label);
  118. this.render(oldPos.map((pos, i) => {
  119. return {
  120. position: oldPos[i],
  121. label: newLabels[i]
  122. }
  123. }));
  124. return this.store.map((line, i) => {
  125. return translateHoriLine(
  126. line, newPos[i], oldPos[i]
  127. );
  128. });
  129. }
  130. },
  131. yRegions: {
  132. layerClass: 'y-regions',
  133. makeElements(data) {
  134. return data.map(region =>
  135. yRegion(region.start, region.end, this.constants.width,
  136. region.label)
  137. );
  138. },
  139. animateElements(newData) {
  140. [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);
  141. let newPos = newData.map(d => d.end);
  142. let newLabels = newData.map(d => d.label);
  143. let newStarts = newData.map(d => d.start);
  144. let oldPos = this.oldData.map(d => d.end);
  145. let oldLabels = this.oldData.map(d => d.label);
  146. let oldStarts = this.oldData.map(d => d.start);
  147. this.render(oldPos.map((pos, i) => {
  148. return {
  149. start: oldStarts[i],
  150. end: oldPos[i],
  151. label: newLabels[i]
  152. }
  153. }));
  154. let animateElements = [];
  155. this.store.map((rectGroup, i) => {
  156. animateElements = animateElements.concat(animateRegion(
  157. rectGroup, newStarts[i], newPos[i], oldPos[i]
  158. ));
  159. });
  160. return animateElements;
  161. }
  162. },
  163. barGraph: {
  164. layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },
  165. makeElements(data) {
  166. let c = this.constants;
  167. this.unitType = 'bar';
  168. return data.yPositions.map((y, j) => {
  169. return datasetBar(
  170. data.xPositions[j],
  171. y,
  172. data.barWidth,
  173. c.color,
  174. data.labels[j],
  175. j,
  176. data.offsets[j],
  177. {
  178. zeroLine: data.zeroLine,
  179. barsWidth: data.barsWidth,
  180. minHeight: c.minHeight
  181. }
  182. )
  183. });
  184. },
  185. animateElements(newData) {
  186. let c = this.constants;
  187. let newXPos = newData.xPositions;
  188. let newYPos = newData.yPositions;
  189. let newOffsets = newData.offsets;
  190. let newLabels = newData.labels;
  191. let oldXPos = this.oldData.xPositions;
  192. let oldYPos = this.oldData.yPositions;
  193. let oldOffsets = this.oldData.offsets;
  194. let oldLabels = this.oldData.labels;
  195. [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);
  196. [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);
  197. [oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);
  198. [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
  199. this.render({
  200. xPositions: oldXPos,
  201. yPositions: oldYPos,
  202. offsets: oldOffsets,
  203. labels: newLabels,
  204. zeroLine: this.oldData.zeroLine,
  205. barsWidth: this.oldData.barsWidth,
  206. barWidth: this.oldData.barWidth,
  207. });
  208. let animateElements = [];
  209. this.store.map((bar, i) => {
  210. animateElements = animateElements.concat(animateBar(
  211. bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i], c.index,
  212. {zeroLine: newData.zeroLine}
  213. ));
  214. });
  215. return animateElements;
  216. }
  217. },
  218. lineGraph: {
  219. layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },
  220. makeElements(data) {
  221. let c = this.constants;
  222. this.unitType = 'dot';
  223. this.paths = getPaths(
  224. data.xPositions,
  225. data.yPositions,
  226. c.color,
  227. {
  228. heatline: c.heatline,
  229. regionFill: c.regionFill
  230. },
  231. {
  232. svgDefs: c.svgDefs,
  233. zeroLine: data.zeroLine
  234. }
  235. )
  236. this.dots = []
  237. if(!c.hideDots) {
  238. this.dots = data.yPositions.map((y, j) => {
  239. return datasetDot(
  240. data.xPositions[j],
  241. y,
  242. data.radius,
  243. c.color,
  244. (c.valuesOverPoints ? data.values[j] : ''),
  245. j
  246. )
  247. });
  248. }
  249. return Object.values(this.paths).concat(this.dots);
  250. // return this.dots;
  251. },
  252. animateElements(newData) {
  253. let c = this.constants;
  254. let newXPos = newData.xPositions;
  255. let newYPos = newData.yPositions;
  256. let newValues = newData.values;
  257. let oldXPos = this.oldData.xPositions;
  258. let oldYPos = this.oldData.yPositions;
  259. let oldValues = this.oldData.values;
  260. [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);
  261. [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);
  262. [oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);
  263. this.render({
  264. xPositions: oldXPos,
  265. yPositions: oldYPos,
  266. values: newValues,
  267. zeroLine: this.oldData.zeroLine,
  268. radius: this.oldData.radius,
  269. });
  270. let animateElements = [];
  271. animateElements = animateElements.concat(animatePath(
  272. this.paths, newXPos, newYPos, newData.zeroLine));
  273. if(this.dots.length) {
  274. this.dots.map((dot, i) => {
  275. animateElements = animateElements.concat(animateDot(
  276. dot, newXPos[i], newYPos[i]));
  277. });
  278. }
  279. return animateElements;
  280. }
  281. }
  282. }
  283. export function getComponent(name, constants, getData) {
  284. let keys = Object.keys(componentConfigs).filter(k => name.includes(k));
  285. let config = componentConfigs[keys[0]];
  286. Object.assign(config, {
  287. constants: constants,
  288. getData: getData
  289. })
  290. return new ChartComponent(config);
  291. }