@@ -94,14 +94,21 @@ const svg = computed(() => {
9494 }
9595});
9696
97+ const marginalSize = computed (() => {
98+ if (! scatterConfig .value .style .layout .marginalBars .show ) {
99+ return 0
100+ }
101+ return scatterConfig .value .style .layout .marginalBars .size + scatterConfig .value .style .layout .marginalBars .offset
102+ })
103+
97104const drawingArea = computed (() => {
98105 return {
99- top: scatterConfig .value .style .layout .padding .top ,
100- right: svg .value .width - scatterConfig .value .style .layout .padding .right ,
106+ top: scatterConfig .value .style .layout .padding .top + marginalSize . value ,
107+ right: svg .value .width - scatterConfig .value .style .layout .padding .right - marginalSize . value ,
101108 bottom: svg .value .height - scatterConfig .value .style .layout .padding .bottom ,
102109 left: scatterConfig .value .style .layout .padding .left ,
103- height: svg .value .height - scatterConfig .value .style .layout .padding .top - scatterConfig .value .style .layout .padding .bottom ,
104- width: svg .value .width - scatterConfig .value .style .layout .padding .left - scatterConfig .value .style .layout .padding .right
110+ height: svg .value .height - scatterConfig .value .style .layout .padding .top - scatterConfig .value .style .layout .padding .bottom - marginalSize . value ,
111+ width: svg .value .width - scatterConfig .value .style .layout .padding .left - scatterConfig .value .style .layout .padding .right - marginalSize . value
105112 }
106113});
107114
@@ -256,6 +263,61 @@ function getData() {
256263 return drawableDataset .value ;
257264}
258265
266+ function aggregateCoordinates (arr , scale ) {
267+ const flattened = arr .flatMap (a => {
268+ return a .plots .map ((p ) => {
269+ return {
270+ x: p .x ,
271+ y: p .y
272+ }
273+ })
274+ });
275+
276+ let xMin = Infinity , xMax = - Infinity , yMin = Infinity , yMax = - Infinity ;
277+
278+ flattened .forEach (({x, y}) => {
279+ xMin = Math .min (xMin, x);
280+ xMax = Math .max (xMax, x);
281+ yMin = Math .min (yMin, y);
282+ yMax = Math .max (yMax, y);
283+ });
284+
285+ const totalX = xMax - xMin;
286+ const totalY = yMax - yMin;
287+ const chunkSizeX = totalX / scale;
288+ const chunkSizeY = totalY / scale;
289+ const xCounts = Array (scale).fill (0 );
290+ const yCounts = Array (scale).fill (0 );
291+
292+ flattened .forEach (({ x, y }) => {
293+ const xIndex = Math .floor ((x - xMin) / chunkSizeX);
294+ const yIndex = Math .floor ((y - yMin) / chunkSizeY);
295+ if (! xCounts[xIndex]) {
296+ xCounts[xIndex] = 0 ;
297+ }
298+ if (! yCounts[yIndex]) {
299+ yCounts[yIndex] = 0 ;
300+ }
301+ xCounts[xIndex] += 1 ;
302+ yCounts[yIndex] += 1 ;
303+ });
304+
305+ const avgX = [];
306+ const avgY = [];
307+ for (let i = 0 ; i < scale; i += 1 ) {
308+ avgX .push (xMin + (i + 0.5 ) * chunkSizeX);
309+ avgY .push (yMin + (i + 0.5 ) * chunkSizeY);
310+ }
311+ const maxX = Math .max (... xCounts);
312+ const maxY = Math .max (... yCounts);
313+ return { x: xCounts, y: yCounts, avgX, avgY, maxX, maxY };
314+ }
315+
316+ const scale = ref (20 );
317+ const marginalBars = computed (() => {
318+ return aggregateCoordinates (mutableDataset .value , scale .value )
319+ })
320+
259321const selectedPlotId = ref (undefined );
260322const selectedPlot = ref (null );
261323const dataTooltipSlot = ref (null );
@@ -590,6 +652,46 @@ defineExpose({
590652 < / g>
591653 < / g>
592654
655+ <!-- MARGINAL BARS -->
656+ < g v- if = " scatterConfig.style.layout.marginalBars.show" >
657+ < defs>
658+ < linearGradient : id= " `marginal_x_${uid}`" x1= " 0%" y1= " 0%" x2= " 0%" y2= " 100%" >
659+ < stop offset= " 0%" : stop- color= " scatterConfig.style.layout.marginalBars.fill" / >
660+ < stop offset= " 100%" : stop- color= " scatterConfig.style.backgroundColor" / >
661+ < / linearGradient>
662+ < linearGradient : id= " `marginal_y_${uid}`" x1= " 0%" x2= " 100%" y1= " 0%" y2= " 0%" >
663+ < stop offset= " 0%" : stop- color= " scatterConfig.style.backgroundColor" / >
664+ < stop offset= " 100%" : stop- color= " scatterConfig.style.layout.marginalBars.fill" / >
665+ < / linearGradient>
666+ < / defs>
667+ < g v- for = " (x, i) in marginalBars.x" >
668+ < rect
669+ v- if = " x && marginalBars.avgX[i]"
670+ : x= " marginalBars.avgX[i] - (drawingArea.width / scale / 2)"
671+ : y= " drawingArea.top - scatterConfig.style.layout.marginalBars.offset - x / marginalBars.maxX * scatterConfig.style.layout.marginalBars.size"
672+ : width= " drawingArea.width / scale"
673+ : height= " x / marginalBars.maxX * scatterConfig.style.layout.marginalBars.size"
674+ : fill= " scatterConfig.style.layout.marginalBars.useGradient ? `url(#marginal_x_${uid})` : scatterConfig.style.layout.marginalBars.fill"
675+ : style= " `opacity:${scatterConfig.style.layout.marginalBars.opacity}`"
676+ : stroke= " scatterConfig.style.backgroundColor"
677+ : rx= " scatterConfig.style.layout.marginalBars.borderRadius"
678+ / >
679+ < / g>
680+ < g v- for = " (y, i) in marginalBars.y" >
681+ < rect
682+ v- if = " y && marginalBars.avgY[i]"
683+ : x= " drawingArea.right + scatterConfig.style.layout.marginalBars.offset"
684+ : y= " marginalBars.avgY[i] - (drawingArea.height / scale / 2)"
685+ : height= " drawingArea.height / scale"
686+ : width= " y / marginalBars.maxY * scatterConfig.style.layout.marginalBars.size"
687+ : fill= " scatterConfig.style.layout.marginalBars.useGradient ? `url(#marginal_y_${uid})` : scatterConfig.style.layout.marginalBars.fill"
688+ : style= " `opacity:${scatterConfig.style.layout.marginalBars.opacity}`"
689+ : stroke= " scatterConfig.style.backgroundColor"
690+ : rx= " scatterConfig.style.layout.marginalBars.borderRadius"
691+ / >
692+ < / g>
693+ < / g>
694+
593695 <!-- AXIS LABELS -->
594696 < g v- if = " scatterConfig.style.layout.dataLabels.xAxis.show" >
595697 < text
@@ -652,7 +754,7 @@ defineExpose({
652754 : font- weight= " scatterConfig.style.layout.dataLabels.yAxis.bold ? 'bold' : 'normal'"
653755 : fill= " scatterConfig.style.layout.dataLabels.yAxis.color"
654756 : x= " drawingArea.left + drawingArea.width / 2"
655- : y= " drawingArea.top - 8 - scatterConfig.style.layout.dataLabels.yAxis.fontSize"
757+ : y= " drawingArea.bottom + 8 + scatterConfig.style.layout.dataLabels.yAxis.fontSize"
656758 >
657759 {{ scatterConfig .style .layout .dataLabels .yAxis .name }}
658760 < / text>
0 commit comments