Skip to content

Commit 3c45b1a

Browse files
committed
Improvement - VueUiRelationCircle - Full functionality revamp
1 parent 4c164f9 commit 3c45b1a

File tree

1 file changed

+197
-15
lines changed

1 file changed

+197
-15
lines changed

src/components/vue-ui-relation-circle.vue

Lines changed: 197 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
<script setup>
22
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
33
import {
4+
adaptColorToBackground,
5+
applyDataLabel,
46
convertCustomPalette,
57
createUid,
8+
dataLabel,
69
error,
710
getMissingDatasetAttributes,
811
objectIsEmpty,
912
palette,
1013
themePalettes,
14+
translateSize,
1115
XMLNS
1216
} from "../lib.js";
1317
import { throttle } from "../canvas-lib";
@@ -107,6 +111,9 @@ const limitedDataset = computed(() => {
107111
});
108112
109113
const size = ref(FINAL_CONFIG.value.style.size);
114+
const dataLabelSize = ref(FINAL_CONFIG.value.style.weightLabels.size);
115+
const plotRadius = ref(FINAL_CONFIG.value.style.plot.radius);
116+
const labelFontSize = ref(FINAL_CONFIG.value.style.labels.fontSize);
110117
111118
const svg = ref({
112119
height: FINAL_CONFIG.value.style.size,
@@ -184,6 +191,30 @@ function prepareChart() {
184191
relations.value = [];
185192
createPlots();
186193
createRelations();
194+
195+
dataLabelSize.value = translateSize({
196+
relator: size.value,
197+
adjuster: FINAL_CONFIG.value.style.size,
198+
source: FINAL_CONFIG.value.style.weightLabels.size,
199+
threshold: 6,
200+
fallback: 6
201+
});
202+
203+
plotRadius.value = translateSize({
204+
relator: size.value,
205+
adjuster: FINAL_CONFIG.value.style.size,
206+
source: FINAL_CONFIG.value.style.plot.radius,
207+
threshold: 1,
208+
fallback: 1
209+
});
210+
211+
labelFontSize.value = translateSize({
212+
relator: size.value,
213+
adjuster: FINAL_CONFIG.value.style.size,
214+
source: FINAL_CONFIG.value.style.labels.fontSize,
215+
threshold: 6,
216+
fallback: 6
217+
})
187218
});
188219
189220
resizeObserver.value = new ResizeObserver(handleResize);
@@ -227,31 +258,70 @@ function createPlots() {
227258
let angle = 0;
228259
let regAngle = 0;
229260
limitedDataset.value.forEach((plot, i) => {
261+
const totalWeight = plot.weights.reduce((a, b) => a + b, 0);
230262
const x = radius.value * Math.cos(angle) + (svg.value.width / 2);
231263
const y = radius.value * Math.sin(angle) + svg.value.height / 2 + FINAL_CONFIG.value.style.circle.offsetY;
232-
circles.value.push({x,y, ...plot, color: plot.color ? plot.color : customPalette.value[i] ? customPalette.value[i] : palette[i], regAngle});
264+
circles.value.push({x,y, ...plot, color: plot.color ? plot.color : customPalette.value[i] ? customPalette.value[i] : palette[i], regAngle, totalWeight });
233265
angle += angleGap;
234266
regAngle += regAngleGap
235267
});
236268
}
237269
270+
function getMiddlePoint(point1, point2) {
271+
const middleX = (point1.x + point2.x) / 2;
272+
const middleY = (point1.y + point2.y) / 2;
273+
return { x: middleX, y: middleY };
274+
}
275+
238276
function createRelations() {
277+
relations.value = [];
239278
circles.value.forEach((plot) => {
240279
let rels = circles.value.filter(c => c.relations.includes(plot.id));
280+
241281
rels.forEach((relation, i) => {
282+
const indexOfRelation = relation.relations.indexOf(plot.id)
242283
relations.value.push({
243-
weight: plot.weights ? plot.weights[i] ? plot.weights[i] : 1 : 1,
284+
weight: relation.weights[indexOfRelation] ? relation.weights[indexOfRelation] : 0,
244285
relationId: `${plot.id}_${relation.id}`,
245286
x1: plot.x,
246287
y1: plot.y,
247288
x2: relation.x,
248289
y2: relation.y,
249290
colorSource: plot.color,
250291
colorTarget: relation.color,
292+
midPointLine: getMiddlePoint({x: plot.x, y: plot.y}, {x: relation.x, y: relation.y}),
293+
midPointBezier: getBezierMidpoint({
294+
x1: plot.x,
295+
x2: relation.x,
296+
y1: plot.y,
297+
y2: relation.y
298+
}),
251299
...plot
252-
})
253-
})
254-
})
300+
});
301+
});
302+
});
303+
}
304+
305+
function getBezierMidpoint(relation) {
306+
const P0 = { x: relation.x1, y: relation.y1 };
307+
const P3 = { x: relation.x2, y: relation.y2 };
308+
const P1 = { x: relation.x1, y: relation.y1 };
309+
const P2 = {
310+
x: svg.value.width / 2,
311+
y: svg.value.height / 2 + FINAL_CONFIG.value.style.circle.offsetY
312+
};
313+
const t = 0.5;
314+
const x = Math.pow(1 - t, 3) * P0.x +
315+
3 * Math.pow(1 - t, 2) * t * P1.x +
316+
3 * (1 - t) * Math.pow(t, 2) * P2.x +
317+
Math.pow(t, 3) * P3.x;
318+
319+
const y = Math.pow(1 - t, 3) * P0.y +
320+
3 * Math.pow(1 - t, 2) * t * P1.y +
321+
3 * (1 - t) * Math.pow(t, 2) * P2.y +
322+
Math.pow(t, 3) * P3.y;
323+
324+
return { x, y };
255325
}
256326
257327
const maxWeight = computed(() => {
@@ -271,11 +341,7 @@ function getCircleOpacity(plot) {
271341
}
272342
273343
function getLineColor(plot) {
274-
if (Object.hasOwn(selectedPlot.value, 'x')) {
275-
return plot.colorTarget;
276-
} else {
277-
return plot.colorSource;
278-
}
344+
return plot.colorSource
279345
}
280346
281347
function getLineOpacityAndWidth(plot) {
@@ -290,6 +356,18 @@ function getLineOpacityAndWidth(plot) {
290356
}
291357
}
292358
359+
function showLabel(plot) {
360+
if(Object.hasOwn(selectedPlot.value, 'x')) {
361+
if (selectedRelations.value.includes(plot.id) && plot.relationId === `${plot.id}_${selectedPlot.value.id}` || plot.relationId === `${selectedPlot.value.id}_${plot.id}`) {
362+
return true
363+
} else {
364+
return false
365+
}
366+
} else {
367+
return false
368+
}
369+
}
370+
293371
function getTextAnchor(plot) {
294372
if (plot.regAngle > 90 && plot.regAngle < 270) {
295373
return "end";
@@ -335,7 +413,8 @@ function selectPlot(plot) {
335413
}
336414
337415
function calcLinkWidth(plot) {
338-
return plot.weight / maxWeight.value * FINAL_CONFIG.value.style.links.maxWidth;
416+
const w = plot.weight / maxWeight.value * FINAL_CONFIG.value.style.links.maxWidth;
417+
return Math.max(0.3, w);
339418
}
340419
341420
const isFullscreen = ref(false)
@@ -463,11 +542,56 @@ defineExpose({
463542
:stroke-width="calcLinkWidth(relation)"
464543
stroke-linecap="round"
465544
/>
545+
<g v-for="(relation, i) in relations" style="pointer-events: none;">
546+
<slot
547+
name="dataLabel"
548+
v-bind="{
549+
x: relation.midPointBezier.x,
550+
y: relation.midPointBezier.y,
551+
color: getLineColor(relation),
552+
weight: relation.weight,
553+
fontSize: dataLabelSize
554+
}"
555+
v-if="showLabel(relation)"
556+
/>
557+
<circle
558+
v-if="showLabel(relation) && !$slots.dataLabel"
559+
:cx="relation.midPointBezier.x"
560+
:cy="relation.midPointBezier.y"
561+
:fill="getLineColor(relation)"
562+
:r="dataLabelSize"
563+
:stroke="FINAL_CONFIG.style.backgroundColor"
564+
stroke-width="1"
565+
/>
566+
<text
567+
v-if="showLabel(relation) && !$slots.dataLabel"
568+
:x="relation.midPointBezier.x"
569+
:y="relation.midPointBezier.y + dataLabelSize / 3"
570+
:fill="adaptColorToBackground(getLineColor(relation))"
571+
text-anchor="middle"
572+
:font-size="dataLabelSize"
573+
>
574+
{{
575+
applyDataLabel(
576+
FINAL_CONFIG.style.weightLabels.formatter,
577+
relation.weight,
578+
dataLabel({
579+
p: FINAL_CONFIG.style.weightLabels.prefix,
580+
v: relation.weight,
581+
s: FINAL_CONFIG.style.weightLabels.suffix,
582+
r: FINAL_CONFIG.style.weightLabels.rounding
583+
}),
584+
{ ...relation }
585+
)
586+
}}
587+
</text>
588+
</g>
466589
</g>
467590
<g v-else>
468591
<line v-for="(relation,i) in relations"
469592
:key="`relation_${i}`"
470593
:stroke="getLineColor(relation)"
594+
:stroke-width="calcLinkWidth(relation)"
471595
:style="getLineOpacityAndWidth(relation)"
472596
:x1="relation.x1"
473597
:x2="relation.x2"
@@ -476,6 +600,50 @@ defineExpose({
476600
:class="{'vue-ui-relation-circle-selected': selectedPlot.hasOwnProperty('id') && selectedRelations.includes(relation.id)}"
477601
stroke-linecap="round"
478602
/>
603+
<g v-for="(relation, i) in relations" style="pointer-events: none;">
604+
<slot
605+
name="dataLabel"
606+
v-bind="{
607+
x: relation.midPointLine.x,
608+
y: relation.midPointLine.y,
609+
color: getLineColor(relation),
610+
weight: relation.weight,
611+
fontSize: dataLabelSize
612+
}"
613+
v-if="showLabel(relation)"
614+
/>
615+
<circle
616+
v-if="showLabel(relation) && !$slots.dataLabel && FINAL_CONFIG.style.weightLabels.show"
617+
:cx="relation.midPointLine.x"
618+
:cy="relation.midPointLine.y"
619+
:fill="getLineColor(relation)"
620+
:r="dataLabelSize"
621+
:stroke="FINAL_CONFIG.style.backgroundColor"
622+
stroke-width="1"
623+
/>
624+
<text
625+
v-if="showLabel(relation) && !$slots.dataLabel && FINAL_CONFIG.style.weightLabels.show"
626+
:x="relation.midPointLine.x"
627+
:y="relation.midPointLine.y + dataLabelSize / 3"
628+
:fill="adaptColorToBackground(getLineColor(relation))"
629+
text-anchor="middle"
630+
:font-size="dataLabelSize"
631+
>
632+
{{
633+
applyDataLabel(
634+
FINAL_CONFIG.style.weightLabels.formatter,
635+
relation.weight,
636+
dataLabel({
637+
p: FINAL_CONFIG.style.weightLabels.prefix,
638+
v: relation.weight,
639+
s: FINAL_CONFIG.style.weightLabels.suffix,
640+
r: FINAL_CONFIG.style.weightLabels.rounding
641+
}),
642+
{ ...relation }
643+
)
644+
}}
645+
</text>
646+
</g>
479647
</g>
480648

481649
<text v-for="(plot,i) in circles"
@@ -490,10 +658,22 @@ defineExpose({
490658
transform-origin="start"
491659
:font-weight="selectedPlot.id === plot.id ? '900' : '400'"
492660
:style="`font-family:${FINAL_CONFIG.style.fontFamily};${getTextOpacity(plot)}`"
493-
:font-size="FINAL_CONFIG.style.labels.fontSize"
661+
:font-size="labelFontSize"
494662
:fill="FINAL_CONFIG.style.labels.color"
495663
>
496-
{{plot.label}}
664+
{{plot.label}} ({{
665+
applyDataLabel(
666+
FINAL_CONFIG.style.weightLabels.formatter,
667+
plot.totalWeight,
668+
dataLabel({
669+
p: FINAL_CONFIG.style.weightLabels.prefix,
670+
v: plot.totalWeight,
671+
s: FINAL_CONFIG.style.weightLabels.suffix,
672+
r: FINAL_CONFIG.style.weightLabels.rounding
673+
}),
674+
{ ...plot }
675+
)
676+
}})
497677
</text>
498678

499679
<circle v-for="(plot,i) in circles"
@@ -503,9 +683,11 @@ defineExpose({
503683
:key="`plot_${i}`"
504684
:style="getCircleOpacity(plot)"
505685
class="vue-ui-relation-circle-plot"
506-
:fill="FINAL_CONFIG.style.plot.color"
686+
:fill="FINAL_CONFIG.style.plot.useSerieColor ? plot.color : FINAL_CONFIG.style.plot.color"
687+
:stroke="FINAL_CONFIG.style.backgroundColor"
688+
stroke-width="1"
507689
@click="selectPlot(plot)"
508-
:r="FINAL_CONFIG.style.plot.radius"
690+
:r="plotRadius"
509691
/>
510692
<slot name="svg" :svg="svg"/>
511693
</svg>

0 commit comments

Comments
 (0)