graph.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*!
  2. * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
  4. * v1.0.0-beta.82
  5. */
  6. import { Component, Element, Prop, h, forceUpdate } from "@stencil/core";
  7. import { guid } from "../../utils/guid";
  8. import { area, range, translate } from "./util";
  9. import { createObserver } from "../../utils/observers";
  10. export class Graph {
  11. constructor() {
  12. //--------------------------------------------------------------------------
  13. //
  14. // Properties
  15. //
  16. //--------------------------------------------------------------------------
  17. /**
  18. * Array of tuples describing a single data point ([x, y])
  19. * These data points should be sorted by x-axis value
  20. */
  21. this.data = [];
  22. //--------------------------------------------------------------------------
  23. //
  24. // Private State/Props
  25. //
  26. //--------------------------------------------------------------------------
  27. this.graphId = `calcite-graph-${guid()}`;
  28. this.resizeObserver = createObserver("resize", () => forceUpdate(this));
  29. }
  30. //--------------------------------------------------------------------------
  31. //
  32. // Lifecycle
  33. //
  34. //--------------------------------------------------------------------------
  35. connectedCallback() {
  36. var _a;
  37. (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.el);
  38. }
  39. disconnectedCallback() {
  40. var _a;
  41. (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
  42. }
  43. render() {
  44. const { data, colorStops, el, highlightMax, highlightMin, min, max } = this;
  45. const id = this.graphId;
  46. const { clientHeight: height, clientWidth: width } = el;
  47. // if we have no data, return empty svg
  48. if (!data || data.length === 0) {
  49. return (h("svg", { class: "svg", height: height, preserveAspectRatio: "none", viewBox: `0 0 ${width} ${height}`, width: width }));
  50. }
  51. const { min: rangeMin, max: rangeMax } = range(data);
  52. let currentMin = rangeMin;
  53. let currentMax = rangeMax;
  54. if (min < rangeMin[0] || min > rangeMin[0]) {
  55. currentMin = [min, 0];
  56. }
  57. if (max > rangeMax[0] || max < rangeMax[0]) {
  58. currentMax = [max, rangeMax[1]];
  59. }
  60. const t = translate({ min: currentMin, max: currentMax, width, height });
  61. const [hMinX] = t([highlightMin, currentMax[1]]);
  62. const [hMaxX] = t([highlightMax, currentMax[1]]);
  63. const areaPath = area({ data, min: rangeMin, max: rangeMax, t });
  64. const fill = colorStops ? `url(#linear-gradient-${id})` : undefined;
  65. return (h("svg", { class: "svg", height: height, preserveAspectRatio: "none", viewBox: `0 0 ${width} ${height}`, width: width },
  66. colorStops ? (h("defs", null,
  67. h("linearGradient", { id: `linear-gradient-${id}`, x1: "0", x2: "1", y1: "0", y2: "0" }, colorStops.map(({ offset, color, opacity }) => (h("stop", { offset: `${offset * 100}%`, "stop-color": color, "stop-opacity": opacity })))))) : null,
  68. highlightMin !== undefined ? ([
  69. h("mask", { height: "100%", id: `${id}1`, width: "100%", x: "0%", y: "0%" },
  70. h("path", { d: `
  71. M 0,0
  72. L ${hMinX - 1},0
  73. L ${hMinX - 1},${height}
  74. L 0,${height}
  75. Z
  76. `, fill: "white" })),
  77. h("mask", { height: "100%", id: `${id}2`, width: "100%", x: "0%", y: "0%" },
  78. h("path", { d: `
  79. M ${hMinX + 1},0
  80. L ${hMaxX - 1},0
  81. L ${hMaxX - 1},${height}
  82. L ${hMinX + 1}, ${height}
  83. Z
  84. `, fill: "white" })),
  85. h("mask", { height: "100%", id: `${id}3`, width: "100%", x: "0%", y: "0%" },
  86. h("path", { d: `
  87. M ${hMaxX + 1},0
  88. L ${width},0
  89. L ${width},${height}
  90. L ${hMaxX + 1}, ${height}
  91. Z
  92. `, fill: "white" })),
  93. h("path", { class: "graph-path", d: areaPath, fill: fill, mask: `url(#${id}1)` }),
  94. h("path", { class: "graph-path--highlight", d: areaPath, fill: fill, mask: `url(#${id}2)` }),
  95. h("path", { class: "graph-path", d: areaPath, fill: fill, mask: `url(#${id}3)` })
  96. ]) : (h("path", { class: "graph-path", d: areaPath, fill: fill }))));
  97. }
  98. static get is() { return "calcite-graph"; }
  99. static get encapsulation() { return "shadow"; }
  100. static get originalStyleUrls() { return {
  101. "$": ["graph.scss"]
  102. }; }
  103. static get styleUrls() { return {
  104. "$": ["graph.css"]
  105. }; }
  106. static get properties() { return {
  107. "data": {
  108. "type": "unknown",
  109. "mutable": false,
  110. "complexType": {
  111. "original": "DataSeries",
  112. "resolved": "Point[]",
  113. "references": {
  114. "DataSeries": {
  115. "location": "import",
  116. "path": "./interfaces"
  117. }
  118. }
  119. },
  120. "required": false,
  121. "optional": false,
  122. "docs": {
  123. "tags": [],
  124. "text": "Array of tuples describing a single data point ([x, y])\nThese data points should be sorted by x-axis value"
  125. },
  126. "defaultValue": "[]"
  127. },
  128. "colorStops": {
  129. "type": "unknown",
  130. "mutable": false,
  131. "complexType": {
  132. "original": "ColorStop[]",
  133. "resolved": "ColorStop[]",
  134. "references": {
  135. "ColorStop": {
  136. "location": "import",
  137. "path": "./interfaces"
  138. }
  139. }
  140. },
  141. "required": false,
  142. "optional": false,
  143. "docs": {
  144. "tags": [],
  145. "text": "Array of values describing a single color stop ([offset, color, opacity])\nThese color stops should be sorted by offset value"
  146. }
  147. },
  148. "highlightMin": {
  149. "type": "number",
  150. "mutable": false,
  151. "complexType": {
  152. "original": "number",
  153. "resolved": "number",
  154. "references": {}
  155. },
  156. "required": false,
  157. "optional": false,
  158. "docs": {
  159. "tags": [],
  160. "text": "Start of highlight color if highlighting range"
  161. },
  162. "attribute": "highlight-min",
  163. "reflect": false
  164. },
  165. "highlightMax": {
  166. "type": "number",
  167. "mutable": false,
  168. "complexType": {
  169. "original": "number",
  170. "resolved": "number",
  171. "references": {}
  172. },
  173. "required": false,
  174. "optional": false,
  175. "docs": {
  176. "tags": [],
  177. "text": "End of highlight color if highlighting range"
  178. },
  179. "attribute": "highlight-max",
  180. "reflect": false
  181. },
  182. "min": {
  183. "type": "number",
  184. "mutable": false,
  185. "complexType": {
  186. "original": "number",
  187. "resolved": "number",
  188. "references": {}
  189. },
  190. "required": true,
  191. "optional": false,
  192. "docs": {
  193. "tags": [],
  194. "text": "Lowest point of the range"
  195. },
  196. "attribute": "min",
  197. "reflect": false
  198. },
  199. "max": {
  200. "type": "number",
  201. "mutable": false,
  202. "complexType": {
  203. "original": "number",
  204. "resolved": "number",
  205. "references": {}
  206. },
  207. "required": true,
  208. "optional": false,
  209. "docs": {
  210. "tags": [],
  211. "text": "Highest point of the range"
  212. },
  213. "attribute": "max",
  214. "reflect": false
  215. }
  216. }; }
  217. static get elementRef() { return "el"; }
  218. }