VBarline.mjs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { Fragment as _Fragment, createVNode as _createVNode } from "vue";
  2. // Utilities
  3. import { computed } from 'vue';
  4. import { makeLineProps } from "./util/line.mjs";
  5. import { genericComponent, getPropertyFromItem, getUid, propsFactory, useRender } from "../../util/index.mjs"; // Types
  6. export const makeVBarlineProps = propsFactory({
  7. autoLineWidth: Boolean,
  8. ...makeLineProps()
  9. }, 'VBarline');
  10. export const VBarline = genericComponent()({
  11. name: 'VBarline',
  12. props: makeVBarlineProps(),
  13. setup(props, _ref) {
  14. let {
  15. slots
  16. } = _ref;
  17. const uid = getUid();
  18. const id = computed(() => props.id || `barline-${uid}`);
  19. const autoDrawDuration = computed(() => Number(props.autoDrawDuration) || 500);
  20. const hasLabels = computed(() => {
  21. return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
  22. });
  23. const lineWidth = computed(() => parseFloat(props.lineWidth) || 4);
  24. const totalWidth = computed(() => Math.max(props.modelValue.length * lineWidth.value, Number(props.width)));
  25. const boundary = computed(() => {
  26. return {
  27. minX: 0,
  28. maxX: totalWidth.value,
  29. minY: 0,
  30. maxY: parseInt(props.height, 10)
  31. };
  32. });
  33. const items = computed(() => props.modelValue.map(item => getPropertyFromItem(item, props.itemValue, item)));
  34. function genBars(values, boundary) {
  35. const {
  36. minX,
  37. maxX,
  38. minY,
  39. maxY
  40. } = boundary;
  41. const totalValues = values.length;
  42. let maxValue = props.max != null ? Number(props.max) : Math.max(...values);
  43. let minValue = props.min != null ? Number(props.min) : Math.min(...values);
  44. if (minValue > 0 && props.min == null) minValue = 0;
  45. if (maxValue < 0 && props.max == null) maxValue = 0;
  46. const gridX = maxX / totalValues;
  47. const gridY = (maxY - minY) / (maxValue - minValue || 1);
  48. const horizonY = maxY - Math.abs(minValue * gridY);
  49. return values.map((value, index) => {
  50. const height = Math.abs(gridY * value);
  51. return {
  52. x: minX + index * gridX,
  53. y: horizonY - height + +(value < 0) * height,
  54. height,
  55. value
  56. };
  57. });
  58. }
  59. const parsedLabels = computed(() => {
  60. const labels = [];
  61. const points = genBars(items.value, boundary.value);
  62. const len = points.length;
  63. for (let i = 0; labels.length < len; i++) {
  64. const item = points[i];
  65. let value = props.labels[i];
  66. if (!value) {
  67. value = typeof item === 'object' ? item.value : item;
  68. }
  69. labels.push({
  70. x: item.x,
  71. value: String(value)
  72. });
  73. }
  74. return labels;
  75. });
  76. const bars = computed(() => genBars(items.value, boundary.value));
  77. const offsetX = computed(() => (Math.abs(bars.value[0].x - bars.value[1].x) - lineWidth.value) / 2);
  78. useRender(() => {
  79. const gradientData = !props.gradient.slice().length ? [''] : props.gradient.slice().reverse();
  80. return _createVNode("svg", {
  81. "display": "block"
  82. }, [_createVNode("defs", null, [_createVNode("linearGradient", {
  83. "id": id.value,
  84. "gradientUnits": "userSpaceOnUse",
  85. "x1": props.gradientDirection === 'left' ? '100%' : '0',
  86. "y1": props.gradientDirection === 'top' ? '100%' : '0',
  87. "x2": props.gradientDirection === 'right' ? '100%' : '0',
  88. "y2": props.gradientDirection === 'bottom' ? '100%' : '0'
  89. }, [gradientData.map((color, index) => _createVNode("stop", {
  90. "offset": index / Math.max(gradientData.length - 1, 1),
  91. "stop-color": color || 'currentColor'
  92. }, null))])]), _createVNode("clipPath", {
  93. "id": `${id.value}-clip`
  94. }, [bars.value.map(item => _createVNode("rect", {
  95. "x": item.x + offsetX.value,
  96. "y": item.y,
  97. "width": lineWidth.value,
  98. "height": item.height,
  99. "rx": typeof props.smooth === 'number' ? props.smooth : props.smooth ? 2 : 0,
  100. "ry": typeof props.smooth === 'number' ? props.smooth : props.smooth ? 2 : 0
  101. }, [props.autoDraw && _createVNode(_Fragment, null, [_createVNode("animate", {
  102. "attributeName": "y",
  103. "from": item.y + item.height,
  104. "to": item.y,
  105. "dur": `${autoDrawDuration.value}ms`,
  106. "fill": "freeze"
  107. }, null), _createVNode("animate", {
  108. "attributeName": "height",
  109. "from": "0",
  110. "to": item.height,
  111. "dur": `${autoDrawDuration.value}ms`,
  112. "fill": "freeze"
  113. }, null)])]))]), hasLabels.value && _createVNode("g", {
  114. "key": "labels",
  115. "style": {
  116. textAnchor: 'middle',
  117. dominantBaseline: 'mathematical',
  118. fill: 'currentColor'
  119. }
  120. }, [parsedLabels.value.map((item, i) => _createVNode("text", {
  121. "x": item.x + offsetX.value + lineWidth.value / 2,
  122. "y": parseInt(props.height, 10) - 2 + (parseInt(props.labelSize, 10) || 7 * 0.75),
  123. "font-size": Number(props.labelSize) || 7
  124. }, [slots.label?.({
  125. index: i,
  126. value: item.value
  127. }) ?? item.value]))]), _createVNode("g", {
  128. "clip-path": `url(#${id.value}-clip)`,
  129. "fill": `url(#${id.value})`
  130. }, [_createVNode("rect", {
  131. "x": 0,
  132. "y": 0,
  133. "width": Math.max(props.modelValue.length * lineWidth.value, Number(props.width)),
  134. "height": props.height
  135. }, null)])]);
  136. });
  137. }
  138. });
  139. //# sourceMappingURL=VBarline.mjs.map