Skip to content

Commit 042880a

Browse files
committed
VueUiXy add smooth curve option for line types in SVG mode
1 parent 29f6f51 commit 042880a

File tree

4 files changed

+83
-41
lines changed

4 files changed

+83
-41
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-data-ui",
33
"private": false,
4-
"version": "1.8.9",
4+
"version": "1.9.0",
55
"type": "module",
66
"description": "A user-empowering data visualization Vue components library",
77
"keywords": [

src/App.vue

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ const dataset2 = ref([
9696
name: "Series 3",
9797
series: [
9898
-55,
99-
-34,
99+
34,
100100
-21,
101-
-13,
101+
13,
102102
-8,
103-
-5,
103+
5,
104104
-3,
105-
-2,
106-
-1,
105+
2,
107106
-1,
107+
1,
108108
0,
109109
1,
110110
1,
@@ -118,6 +118,7 @@ const dataset2 = ref([
118118
55,
119119
],
120120
useArea: true,
121+
smooth: true,
121122
type: "line",
122123
dashed: false,
123124
dataLabels: true,
@@ -3530,6 +3531,25 @@ const showLocalTest = ref(false);
35303531
<button @click="printRelation">PRINT RELATION CIRCLE</button>
35313532
<button @click="printThermo">PRINT THERMO</button>
35323533

3534+
<div style="max-width: 1000px; margin: 0 auto">
3535+
<VueUiXy
3536+
ref="xytest"
3537+
:config="{ ...config, useCanvas: false, useCssAnimation: false }"
3538+
:dataset="dataset2"
3539+
v-if="!showLocalTest"
3540+
@selectLegend="selectLegendXY"
3541+
@selectX="selectX"
3542+
/>
3543+
<XyTest
3544+
ref="xytest"
3545+
:config="{ ...config, useCanvas: false }"
3546+
:dataset="dataset2"
3547+
v-if="showLocalTest"
3548+
@selectLegend="selectLegendXY"
3549+
@selectX="selectX"
3550+
/>
3551+
</div>
3552+
35333553
<div style="max-width: 1000px; margin: 0 auto; margin-bottom: 48px">
35343554
<VueUiSparkHistogram v-if="!showLocalTest" :dataset="histoDataset" :config="histoConfig"/>
35353555
<HistoTest v-if="showLocalTest" :dataset="histoDataset" :config="histoConfig"/>
@@ -3634,25 +3654,6 @@ const showLocalTest = ref(false);
36343654
/>
36353655
</div>
36363656

3637-
<div style="max-width: 1000px; margin: 0 auto">
3638-
<VueUiXy
3639-
ref="xytest"
3640-
:config="{ ...config, useCanvas: false, useCssAnimation: false }"
3641-
:dataset="dataset2"
3642-
v-if="!showLocalTest"
3643-
@selectLegend="selectLegendXY"
3644-
@selectX="selectX"
3645-
/>
3646-
<XyTest
3647-
ref="xytest"
3648-
:config="{ ...config, useCanvas: false }"
3649-
:dataset="dataset2"
3650-
v-if="showLocalTest"
3651-
@selectLegend="selectLegendXY"
3652-
@selectX="selectX"
3653-
/>
3654-
</div>
3655-
36563657
<div style="maw-width:300px;margin: 0 auto; margin-top: 24px; margin-bottom: 24px;">
36573658
<StackTest v-if="showLocalTest" :config="stackConfig" :dataset="stackDataset"/>
36583659
<VueUiSparkStackbar v-if="!showLocalTest" :config="stackConfig" :dataset="stackDataset"/>

src/components/vue-ui-xy.vue

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -228,21 +228,26 @@
228228
<!-- LINES -->
229229
<g v-for="(serie, i) in lineSet" :key="`serie_line_${i}`" :class="`serie_line_${i}`">
230230
<g v-if="serie.useArea">
231-
<path :d="`M${serie.area}Z`" :fill="chartConfig.line.area.useGradient ? `url(#areaGradient_${i}_${uniqueId})` : `${serie.color}${opacity[chartConfig.line.area.opacity]}`"/>
231+
<path v-if="serie.smooth" :d="`M ${serie.plots[0].x},${drawingArea.bottom} ${serie.curve} L ${serie.plots.at(-1).x},${drawingArea.bottom} Z`" :fill="chartConfig.line.area.useGradient ? `url(#areaGradient_${i}_${uniqueId})` : `${serie.color}${opacity[chartConfig.line.area.opacity]}`"/>
232+
233+
<path v-else :d="`M${serie.area}Z`" :fill="chartConfig.line.area.useGradient ? `url(#areaGradient_${i}_${uniqueId})` : `${serie.color}${opacity[chartConfig.line.area.opacity]}`"/>
232234
</g>
233-
<g v-for="(plot, j) in serie.plots" :key="`line_${i}_${j}`">
234-
<line
235-
v-if="j < serie.plots.length - 1 && canShowValue(plot.value) && canShowValue(serie.plots[j+1].value)"
236-
:x1="plot.x"
237-
:x2="serie.plots[j+1].x"
238-
:y1="plot.y"
239-
:y2="serie.plots[j+1].y"
240-
:stroke="serie.color"
241-
:stroke-width="chartConfig.line.strokeWidth"
242-
:stroke-dasharray="serie.dashed ? chartConfig.line.strokeWidth * 2 : 0"
243-
stroke-linejoin="round"
244-
stroke-linecap="round"
245-
/>
235+
<path v-if="serie.smooth" :d="`M${serie.curve}`" :stroke="serie.color" :stroke-width="chartConfig.line.strokeWidth" :stroke-dasharray="serie.dashed ? chartConfig.line.strokeWidth * 2 : 0" fill="none" />
236+
<g v-else>
237+
<g v-for="(plot, j) in serie.plots" :key="`line_${i}_${j}`">
238+
<line
239+
v-if="j < serie.plots.length - 1 && canShowValue(plot.value) && canShowValue(serie.plots[j+1].value)"
240+
:x1="plot.x"
241+
:x2="serie.plots[j+1].x"
242+
:y1="plot.y"
243+
:y2="serie.plots[j+1].y"
244+
:stroke="serie.color"
245+
:stroke-width="chartConfig.line.strokeWidth"
246+
:stroke-dasharray="serie.dashed ? chartConfig.line.strokeWidth * 2 : 0"
247+
stroke-linejoin="round"
248+
stroke-linecap="round"
249+
/>
250+
</g>
246251
</g>
247252
<g v-for="(plot, j) in serie.plots"
248253
:key="`circle_line_${i}_${j}`">
@@ -757,8 +762,10 @@ export default {
757762
value: datapoint.absoluteValues[j],
758763
}
759764
});
765+
const curve = this.createSmoothPath(plots);
760766
return {
761767
...datapoint,
768+
curve,
762769
plots,
763770
area: !datapoint.useArea ? '' : this.createArea(plots)
764771
}
@@ -1076,6 +1083,40 @@ export default {
10761083
});
10771084
return [ start.x, start.y, ...path, end.x, end.y].toString();
10781085
},
1086+
createSmoothPath(points) {
1087+
const smoothing = 0.2;
1088+
function line(pointA, pointB) {
1089+
const lengthX = pointB.x - pointA.x;
1090+
const lengthY = pointB.y - pointA.y;
1091+
return {
1092+
length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
1093+
angle: Math.atan2(lengthY, lengthX)
1094+
};
1095+
}
1096+
function controlPoint(current, previous, next, reverse) {
1097+
const p = previous || current;
1098+
const n = next || current;
1099+
const o = line(p, n);
1100+
1101+
const angle = o.angle + (reverse ? Math.PI : 0);
1102+
const length = o.length * smoothing;
1103+
1104+
const x = current.x + Math.cos(angle) * length;
1105+
const y = current.y + Math.sin(angle) * length;
1106+
return { x, y };
1107+
}
1108+
function bezierCommand(point, i, a) {
1109+
const cps = controlPoint(a[i - 1], a[i - 2], point);
1110+
const cpe = controlPoint(point, a[i - 1], a[i + 1], true);
1111+
return `C ${cps.x},${cps.y} ${cpe.x},${cpe.y} ${point.x},${point.y}`;
1112+
}
1113+
const d = points.reduce((acc, point, i, a) => i === 0
1114+
? `${point.x},${point.y} `
1115+
: `${acc} ${bezierCommand(point, i, a)} `
1116+
, '');
1117+
1118+
return d;
1119+
},
10791120
/////////////////////////////// CANVAS /////////////////////////////////
10801121
createCanvasArea(plots) {
10811122
const start = { x: plots[0].x, y: this.zero };

0 commit comments

Comments
 (0)