11<script setup>
22import { ref , computed , nextTick , onMounted } from " vue" ;
3- import { opacity , createUid , createCsvContent , downloadCsv } from " ../lib" ;
3+ import { opacity , createUid , createCsvContent , downloadCsv , interpolateColorHex , adaptColorToBackground } from " ../lib" ;
44import mainConfig from " ../default_configs.json" ;
55import pdf from " ../pdf" ;
66import img from " ../img" ;
@@ -80,14 +80,18 @@ const svg = computed(() => {
8080 }
8181});
8282
83+ const legendPosition = computed (() => {
84+ return heatmapConfig .value .style .legend .position ;
85+ })
86+
8387const drawingArea = computed (() => {
8488 return {
8589 top: heatmapConfig .value .style .layout .padding .top + (mutableConfig .value .inside ? 36 : 0 ) ,
8690 left: heatmapConfig .value .style .layout .padding .left ,
87- right: svg .value .width - heatmapConfig .value .style .layout .padding .right ,
91+ right: svg .value .width - heatmapConfig .value .style .layout .padding .right - ( legendPosition . value === " right " && heatmapConfig . value . style . legend . show ? 92 : 0 ) ,
8892 bottom: svg .value .height - heatmapConfig .value .style .layout .padding .bottom ,
8993 height: svg .value .height - heatmapConfig .value .style .layout .padding .top - heatmapConfig .value .style .layout .padding .bottom ,
90- width: svg .value .width - heatmapConfig .value .style .layout .padding .right - heatmapConfig .value .style .layout .padding .left
94+ width: svg .value .width - heatmapConfig .value .style .layout .padding .right - heatmapConfig .value .style .layout .padding .left - ( legendPosition . value === " right " && heatmapConfig . value . style . legend . show ? 92 : 0 )
9195 }
9296});
9397
@@ -132,6 +136,7 @@ const mutableDataset = computed(() => {
132136 if (v >= average .value ) {
133137 return {
134138 side: " up" ,
139+ color: interpolateColorHex (heatmapConfig .value .style .layout .cells .colors .cold , heatmapConfig .value .style .layout .cells .colors .hot , minValue .value , maxValue .value , v),
135140 ratio: Math .abs ((Math .abs (v - average .value ) / Math .abs (maxValue .value - average .value ))) > 1 ? 1 : Math .abs ((Math .abs (v - average .value ) / Math .abs (maxValue .value - average .value ))),
136141 value: v,
137142 yAxisName: ds .name ,
@@ -142,6 +147,7 @@ const mutableDataset = computed(() => {
142147 return {
143148 side: " down" ,
144149 ratio: Math .abs (1 - (Math .abs (v) / Math .abs (average .value ))) > 1 ? 1 : Math .abs (1 - (Math .abs (v) / Math .abs (average .value ))),
150+ color: interpolateColorHex (heatmapConfig .value .style .layout .cells .colors .cold , heatmapConfig .value .style .layout .cells .colors .hot , minValue .value , maxValue .value , v),
145151 value: v,
146152 yAxisName: ds .name ,
147153 xAxisName: dataLabels .value .xLabels [i],
@@ -160,7 +166,7 @@ function useTooltip(datapoint) {
160166 let html = " " ;
161167
162168 html += ` <div data-cy="heatmap-tootlip-name">${ yAxisName} ${ xAxisName ? ` ${ xAxisName} ` : ' ' } </div>` ;
163- html += ` <div data-cy="heatmap-tooltip-value" style="margin-top:6px;padding-top:6px;border-top:1px solid #e1e5e8;font-weight:bold"> ${ isNaN (value) ? " -" : Number (value .toFixed (heatmapConfig .value .style .tooltip .roundingValue )).toLocaleString ()} </div>`
169+ html += ` <div data-cy="heatmap-tooltip-value" style="margin-top:6px;padding-top:6px;border-top:1px solid #e1e5e8;font-weight:bold;display:flex;flex-direction:row;gap:12px;align-items:center;justify-content:center"><span style="color: ${ interpolateColorHex ( heatmapConfig . value . style . layout . cells . colors . cold , heatmapConfig . value . style . layout . cells . colors . hot , minValue . value , maxValue . value , value) } ">⬤</span><span> ${ isNaN (value) ? " -" : Number (value .toFixed (heatmapConfig .value .style .tooltip .roundingValue )).toLocaleString ()} </span> </div>`
164170 tooltipContent .value = ` <div style="font-size:${ heatmapConfig .value .style .tooltip .fontSize } px">${ html} </div>` ;
165171}
166172
@@ -340,7 +346,7 @@ defineExpose({
340346 :y =" drawingArea.top + cellSize.width * i"
341347 :width =" cellSize.width - heatmapConfig.style.layout.cells.spacing"
342348 :height =" cellSize.width - heatmapConfig.style.layout.cells.spacing"
343- :fill =" `${ cell.side === 'up' ? `${heatmapConfig.style.layout.cells.colors.hot}${opacity[Math.round(cell.ratio * 100)]}` : `${heatmapConfig.style.layout.cells.colors.cold}${opacity[Math.round(cell.ratio * 100)]}`}` "
349+ :fill =" cell.color "
344350 :stroke =" hoveredCell && hoveredCell === cell.id ? heatmapConfig.style.layout.cells.selected.color : heatmapConfig.style.backgroundColor"
345351 :stroke-width =" heatmapConfig.style.layout.cells.spacing"
346352 />
@@ -349,7 +355,7 @@ defineExpose({
349355 text-anchor =" middle"
350356 :font-size =" heatmapConfig.style.layout.cells.value.fontSize"
351357 :font-weight =" heatmapConfig.style.layout.cells.value.bold ? 'bold': 'normal'"
352- :fill =" heatmapConfig.style.layout.cells.value. color"
358+ :fill =" adaptColorToBackground(cell. color) "
353359 :x =" (drawingArea.left + cellSize.width * j) + (cellSize.width / 2)"
354360 :y =" (drawingArea.top + cellSize.width * i) + (cellSize.width / 2) + heatmapConfig.style.layout.cells.value.fontSize / 3"
355361 >
@@ -396,6 +402,41 @@ defineExpose({
396402 </text >
397403 </g >
398404
405+ <g v-if =" heatmapConfig.style.legend.show && legendPosition === 'right'" >
406+ <defs >
407+ <linearGradient id =" colorScaleVertical" x2 =" 0%" y2 =" 100%" >
408+ <stop offset =" 0%" :stop-color =" heatmapConfig.style.layout.cells.colors.hot" />
409+ <stop offset =" 100%" :stop-color =" heatmapConfig.style.layout.cells.colors.cold" />
410+ </linearGradient >
411+ </defs >
412+ <text
413+ :x =" drawingArea.right + 36 + 18"
414+ :y =" drawingArea.top - heatmapConfig.style.legend.fontSize * 2"
415+ text-anchor =" middle"
416+ :font-size =" heatmapConfig.style.legend.fontSize * 2"
417+ :fill =" heatmapConfig.style.legend.color"
418+ >
419+ {{ Number(maxValue.toFixed(heatmapConfig.style.legend.roundingValue)).toLocaleString() }}
420+ </text >
421+ <rect
422+ :x =" drawingArea.right + 36"
423+ :y =" drawingArea.top"
424+ :width =" 36"
425+ :height =" drawingArea.height - (heatmapConfig.style.layout.cells.spacing * mutableDataset.length)"
426+ :rx =" heatmapConfig.style.legend.scaleBorderRadius"
427+ fill =" url(#colorScaleVertical)"
428+ />
429+ <text
430+ :x =" drawingArea.right + 36 + 18"
431+ :y =" drawingArea.bottom + heatmapConfig.style.legend.fontSize * 2"
432+ text-anchor =" middle"
433+ :font-size =" heatmapConfig.style.legend.fontSize * 2"
434+ :fill =" heatmapConfig.style.legend.color"
435+ >
436+ {{ Number(minValue.toFixed(heatmapConfig.style.legend.roundingValue)).toLocaleString() }}
437+ </text >
438+ </g >
439+
399440 <!-- LEGEND AS G -->
400441 <foreignObject
401442 v-if =" heatmapConfig.style.legend.show && mutableConfig.inside && !isPrinting"
@@ -430,7 +471,7 @@ defineExpose({
430471 </svg >
431472
432473 <!-- LEGEND AS DIV -->
433- <div v-if =" heatmapConfig.style.legend.show && (!mutableConfig.inside || isPrinting)" class =" vue-ui-heatmap-legend" :style =" `background:${heatmapConfig.style.legend.backgroundColor};color:${heatmapConfig.style.legend.color};font-size:${heatmapConfig.style.legend.fontSize}px;padding-bottom:12px;font-weight:${heatmapConfig.style.legend.bold ? 'bold' : ''};display:flex; flex-direction:row;gap:3px;align-items:center;justify-content:center;font-weight:${heatmapConfig.style.legend.bold ? 'bold':'normal'}`" >
474+ <div v-if =" heatmapConfig.style.legend.show && heatmapConfig.style.legend.position === 'bottom' && (!mutableConfig.inside || isPrinting)" class =" vue-ui-heatmap-legend" :style =" `background:${heatmapConfig.style.legend.backgroundColor};color:${heatmapConfig.style.legend.color};font-size:${heatmapConfig.style.legend.fontSize}px;padding-bottom:12px;font-weight:${heatmapConfig.style.legend.bold ? 'bold' : ''};display:flex; flex-direction:row;gap:3px;align-items:center;justify-content:center;font-weight:${heatmapConfig.style.legend.bold ? 'bold':'normal'}`" >
434475 <span data-cy =" heatmap-legend-min" style =" text-align :right " >{{ Number(minValue.toFixed(heatmapConfig.style.legend.roundingValue)).toLocaleString() }}</span >
435476 <svg viewBox =" 0 0 132 12" style =" width : 300px " >
436477 <defs >
0 commit comments