您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

355 行
8.2 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.calcLabels[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.calcLabels;
  89. let oldPos = this.oldData.positions;
  90. let oldLabels = this.oldData.calcLabels;
  91. [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);
  92. [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
  93. this.render({
  94. positions: oldPos,
  95. calcLabels: 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. this.units = 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. return this.units;
  185. },
  186. animateElements(newData) {
  187. let c = this.constants;
  188. let newXPos = newData.xPositions;
  189. let newYPos = newData.yPositions;
  190. let newOffsets = newData.offsets;
  191. let newLabels = newData.labels;
  192. let oldXPos = this.oldData.xPositions;
  193. let oldYPos = this.oldData.yPositions;
  194. let oldOffsets = this.oldData.offsets;
  195. let oldLabels = this.oldData.labels;
  196. [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);
  197. [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);
  198. [oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);
  199. [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);
  200. this.render({
  201. xPositions: oldXPos,
  202. yPositions: oldYPos,
  203. offsets: oldOffsets,
  204. labels: newLabels,
  205. zeroLine: this.oldData.zeroLine,
  206. barsWidth: this.oldData.barsWidth,
  207. barWidth: this.oldData.barWidth,
  208. });
  209. let animateElements = [];
  210. this.store.map((bar, i) => {
  211. animateElements = animateElements.concat(animateBar(
  212. bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i], c.index,
  213. {zeroLine: newData.zeroLine}
  214. ));
  215. });
  216. return animateElements;
  217. }
  218. },
  219. lineGraph: {
  220. layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },
  221. makeElements(data) {
  222. let c = this.constants;
  223. this.unitType = 'dot';
  224. this.paths = {};
  225. if(!c.hideLine) {
  226. this.paths = getPaths(
  227. data.xPositions,
  228. data.yPositions,
  229. c.color,
  230. {
  231. heatline: c.heatline,
  232. regionFill: c.regionFill
  233. },
  234. {
  235. svgDefs: c.svgDefs,
  236. zeroLine: data.zeroLine
  237. }
  238. )
  239. }
  240. this.units = []
  241. if(!c.hideDots) {
  242. this.units = data.yPositions.map((y, j) => {
  243. return datasetDot(
  244. data.xPositions[j],
  245. y,
  246. data.radius,
  247. c.color,
  248. (c.valuesOverPoints ? data.values[j] : ''),
  249. j
  250. )
  251. });
  252. }
  253. return Object.values(this.paths).concat(this.units);
  254. },
  255. animateElements(newData) {
  256. let c = this.constants;
  257. let newXPos = newData.xPositions;
  258. let newYPos = newData.yPositions;
  259. let newValues = newData.values;
  260. let oldXPos = this.oldData.xPositions;
  261. let oldYPos = this.oldData.yPositions;
  262. let oldValues = this.oldData.values;
  263. [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);
  264. [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);
  265. [oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);
  266. this.render({
  267. xPositions: oldXPos,
  268. yPositions: oldYPos,
  269. values: newValues,
  270. zeroLine: this.oldData.zeroLine,
  271. radius: this.oldData.radius,
  272. });
  273. let animateElements = [];
  274. if(Object.keys(this.paths).length) {
  275. animateElements = animateElements.concat(animatePath(
  276. this.paths, newXPos, newYPos, newData.zeroLine));
  277. }
  278. if(this.units.length) {
  279. this.units.map((dot, i) => {
  280. animateElements = animateElements.concat(animateDot(
  281. dot, newXPos[i], newYPos[i]));
  282. });
  283. }
  284. return animateElements;
  285. }
  286. }
  287. }
  288. export function getComponent(name, constants, getData) {
  289. let keys = Object.keys(componentConfigs).filter(k => name.includes(k));
  290. let config = componentConfigs[keys[0]];
  291. Object.assign(config, {
  292. constants: constants,
  293. getData: getData
  294. })
  295. return new ChartComponent(config);
  296. }