@@ -3,7 +3,7 @@ import { ref, watch, computed, nextTick, onMounted, onBeforeUnmount } from 'vue'
33import themes from " ../themes.json" ;
44import Title from ' ../atoms/Title.vue' ;
55import UserOptions from ' ../atoms/UserOptions.vue' ;
6- import { checkNaN , createUid , createWordCloudDatasetFromPlainText } from ' ../lib' ;
6+ import { checkNaN , createUid , createWordCloudDatasetFromPlainText , isFunction } from ' ../lib' ;
77import { debounce } from ' ../canvas-lib' ;
88import {
99 createCsvContent ,
@@ -25,6 +25,7 @@ import { usePrinter } from '../usePrinter';
2525import { useResponsive } from ' ../useResponsive' ;
2626import { useConfig } from ' ../useConfig' ;
2727import PackageVersion from ' ../atoms/PackageVersion.vue' ;
28+ import Tooltip from ' ../atoms/Tooltip.vue' ;
2829
2930const { vue_ui_word_cloud: DEFAULT_CONFIG } = useConfig ();
3031
@@ -65,6 +66,7 @@ const wordCloudChart = ref(null);
6566const chartTitle = ref (null );
6667const titleStep = ref (0 );
6768const tableStep = ref (0 );
69+ const isTooltip = ref (false );
6870
6971const FINAL_CONFIG = computed ({
7072 get : () => {
@@ -181,6 +183,7 @@ const { isPrinting, isImaging, generatePdf, generateImage } = usePrinter({
181183
182184const mutableConfig = ref ({
183185 showTable: FINAL_CONFIG .value .table .show ,
186+ showTooltip: FINAL_CONFIG .value .style .chart .tooltip .show ,
184187});
185188
186189function measureTextSize (text , fontSize , fontFamily = " Arial" ) {
@@ -347,14 +350,56 @@ function toggleTable() {
347350 mutableConfig .value .showTable = ! mutableConfig .value .showTable ;
348351}
349352
353+ function toggleTooltip () {
354+ mutableConfig .value .showTooltip = ! mutableConfig .value .showTooltip ;
355+ }
356+
350357defineExpose ({
351358 getData,
352359 generateCsv,
353360 generatePdf,
354361 generateImage,
355- toggleTable
362+ toggleTable,
363+ toggleTooltip
356364});
357365
366+ const selectedWord = ref (null );
367+ const useCustomFormat = ref (false );
368+ const tooltipContent = ref (' ' );
369+ const dataTooltipSlot = ref (null );
370+
371+ function useTooltip (word ) {
372+ if (! mutableConfig .value .showTooltip ) return ;
373+ selectedWord .value = word .id ;
374+ dataTooltipSlot .value = { datapoint: word, config: FINAL_CONFIG .value };
375+ const customFormat = FINAL_CONFIG .value .style .chart .tooltip .customFormat ;
376+ useCustomFormat .value = false ;
377+
378+ if (isFunction (customFormat)) {
379+ try {
380+ const customFormatString = customFormat ({
381+ datapoint: word,
382+ config: FINAL_CONFIG .value
383+ });
384+ if (typeof customFormatString === ' string' ) {
385+ tooltipContent .value = customFormatString;
386+ useCustomFormat .value = true ;
387+ }
388+ } catch (err) {
389+ console .warn (' Custom format cannot be applied.' );
390+ useCustomFormat .value = false ;
391+ }
392+ }
393+
394+ if (! useCustomFormat .value ) {
395+ let html = ` <svg viewBox="0 0 10 10" height="${ FINAL_CONFIG .value .style .chart .tooltip .fontSize } "><circle cx="5" cy="5" r="5" fill="${ word .color } "/></svg><span>${ word .name } :</span><b>${ (word .value || 0 ).toFixed (FINAL_CONFIG .value .style .chart .tooltip .roundingValue )} </b>` ;
396+
397+ tooltipContent .value = ` <div dir="auto" style="display:flex; gap:4px; align-items:center; jsutify-content:center;">${ html} </div>` ;
398+ }
399+
400+ isTooltip .value = true ;
401+ }
402+
358403 </script >
359404
360405<template >
@@ -392,11 +437,14 @@ defineExpose({
392437 :titles =" { ...FINAL_CONFIG.userOptions.buttonTitles }"
393438 :chartElement =" wordCloudChart"
394439 :position =" FINAL_CONFIG.userOptions.position"
440+ :hasTooltip =" FINAL_CONFIG.style.chart.tooltip.show && FINAL_CONFIG.userOptions.buttons.tooltip"
441+ :isTooltip =" mutableConfig.showTooltip"
395442 @toggleFullscreen =" toggleFullscreen"
396443 @generatePdf =" generatePdf"
397444 @generateCsv =" generateCsv"
398445 @generateImage =" generateImage"
399- @toggleTable =" toggleTable"
446+ @toggleTable =" toggleTable"
447+ @toggleTooltip =" toggleTooltip"
400448 >
401449 <template #optionPdf v-if =" $slots .optionPdf " >
402450 <slot name =" optionPdf" />
@@ -429,10 +477,12 @@ defineExpose({
429477 :font-weight =" FINAL_CONFIG.style.chart.words.bold ? 'bold' : 'normal'" :key =" index"
430478 :x =" word.x" :y =" word.y" :font-size =" word.fontSize"
431479 :transform =" `translate(${word.width / 2}, ${word.height / 2})`"
432- :style =" `animation-delay:${index * FINAL_CONFIG.animationDelayMs}ms !important`"
433- :class =" {'animated': FINAL_CONFIG.useCssAnimation}"
480+ :class =" {'animated': FINAL_CONFIG.useCssAnimation, 'word-selected': selectedWord && selectedWord === word.id && mutableConfig.showTooltip, 'word-not-selected': selectedWord && selectedWord !== word.id && mutableConfig.showTooltip }"
434481 text-anchor =" middle"
435482 dominant-baseline =" middle"
483+ @mouseover =" useTooltip(word)"
484+ @mouseleave =" selectedWord = null; isTooltip = false"
485+ :style =" `animation-delay:${index * FINAL_CONFIG.animationDelayMs}ms !important;`"
436486 >
437487 {{ word.name }}
438488 </text >
@@ -445,6 +495,29 @@ defineExpose({
445495 <slot name =" watermark" v-bind =" { isPrinting: isPrinting || isImaging }" />
446496 </div >
447497
498+ <Tooltip
499+ :show =" mutableConfig.showTooltip && isTooltip"
500+ :backgroundColor =" FINAL_CONFIG.style.chart.tooltip.backgroundColor"
501+ :color =" FINAL_CONFIG.style.chart.tooltip.color"
502+ :fontSize =" FINAL_CONFIG.style.chart.tooltip.fontSize"
503+ :borderRadius =" FINAL_CONFIG.style.chart.tooltip.borderRadius"
504+ :borderColor =" FINAL_CONFIG.style.chart.tooltip.borderColor"
505+ :borderWidth =" FINAL_CONFIG.style.chart.tooltip.borderWidth"
506+ :backgroundOpacity =" FINAL_CONFIG.style.chart.tooltip.backgroundOpacity"
507+ :position =" FINAL_CONFIG.style.chart.tooltip.position"
508+ :offsetY =" FINAL_CONFIG.style.chart.tooltip.offsetY"
509+ :parent =" wordCloudChart"
510+ :content =" tooltipContent"
511+ :isCustom =" useCustomFormat"
512+ >
513+ <template #tooltip-before >
514+ <slot name =" tooltip-before" v-bind =" {...dataTooltipSlot}" ></slot >
515+ </template >
516+ <template #tooltip-after >
517+ <slot name =" tooltip-after" v-bind =" {...dataTooltipSlot}" ></slot >
518+ </template >
519+ </Tooltip >
520+
448521 <div ref =" chartSlicer" :style =" `width:100%;background:transparent`" data-html2canvas-ignore >
449522 <MonoSlicer
450523 v-if =" FINAL_CONFIG.style.chart.zoom.show"
@@ -513,7 +586,7 @@ defineExpose({
513586text .animated {
514587 opacity :0 ;
515588 user-select : none ;
516- animation : word-opacity 0.3 s ease-in forwards ;
589+ animation : word-opacity 0.2 s ease-in forwards ;
517590 transform-origin : center ;
518591}
519592
@@ -525,4 +598,13 @@ text.animated {
525598 opacity : 1 ;
526599 }
527600}
601+
602+ .animated.word-selected {
603+ opacity : 1 ;
604+ }
605+ .word-not-selected {
606+ opacity : 0.5 !important ;
607+ }
608+
609+
528610 </style >
0 commit comments