@@ -1127,41 +1127,69 @@ function calcIndividualRectY(plot) {
11271127
11281128const hoveredIndex = ref (null );
11291129
1130- let RAF_MOUSE_MOVE = 0 ;
1130+ function clientToSvgCoords (evt ) {
1131+ const svgEl = svgRef .value ;
1132+ if (! svgEl) return null ;
1133+
1134+ // Precise mapping (handles fullscreen & letterboxing)
1135+ if (svgEl .createSVGPoint && svgEl .getScreenCTM ) {
1136+ const pt = svgEl .createSVGPoint ();
1137+ pt .x = evt .clientX ;
1138+ pt .y = evt .clientY ;
1139+ const ctm = svgEl .getScreenCTM ();
1140+ if (ctm) {
1141+ const p = pt .matrixTransform (ctm .inverse ());
1142+ return { x: p .x , y: p .y , ok: true };
1143+ }
1144+ }
11311145
1132- function pointInRect (x , y , r ) {
1133- return x >= r .left && x <= r .right && y >= r .top && y <= r .bottom ;
1146+ // Fallback (preserveAspectRatio meet)
1147+ const rect = svgEl .getBoundingClientRect ();
1148+ const vb = svgEl .viewBox ? .baseVal || { x: 0 , y: 0 , width: rect .width , height: rect .height };
1149+ const scale = Math .min (rect .width / vb .width , rect .height / vb .height );
1150+ const drawnW = vb .width * scale;
1151+ const drawnH = vb .height * scale;
1152+ const offsetX = (rect .width - drawnW) / 2 ;
1153+ const offsetY = (rect .height - drawnH) / 2 ;
1154+ const x = (evt .clientX - rect .left - offsetX) / scale + vb .x ;
1155+ const y = (evt .clientY - rect .top - offsetY) / scale + vb .y ;
1156+ return { x, y, ok: true };
11341157}
11351158
1159+ let RAF_MOUSE_MOVE = 0 ;
1160+
11361161function onSvgMouseMove (e ) {
11371162 if (isAnnotator .value ) return ;
11381163
11391164 // cancel any pending raf so a stale one cannot re-open the tooltip
11401165 if (RAF_MOUSE_MOVE ) cancelAnimationFrame (RAF_MOUSE_MOVE );
11411166
1142- const rect = svgRef .value ? .getBoundingClientRect ();
1143-
11441167 RAF_MOUSE_MOVE = requestAnimationFrame (() => {
11451168 RAF_MOUSE_MOVE = 0 ;
11461169
1170+ const svgPt = clientToSvgCoords (e);
11471171 // Mouse may have already left by the time this runs :E
1148- if (! rect || ! pointInRect (e .clientX , e .clientY , rect)) {
1172+ if (! svgPt || ! svgRef .value ) {
1173+ onSvgMouseLeave ();
1174+ return ;
1175+ }
1176+
1177+ // Ignore moves outside drawing area
1178+ const { left , right , top , bottom , width: areaW } = drawingArea .value ;
1179+ if ( svgPt .x < left || svgPt .x > right || svgPt .y < top || svgPt .y > bottom) {
11491180 onSvgMouseLeave ();
11501181 return ;
11511182 }
11521183
1153- const viewBox = svgRef .value .viewBox .baseVal ;
1154- const scaleX = viewBox .width / rect .width ;
1155- const svgX = (e .clientX - rect .left ) * scaleX;
1156- const localX = svgX - drawingArea .value .left ;
1157- const slotW = drawingArea .value .width / maxSeries .value ;
1184+ const localX = svgPt .x - left;
1185+ const slotW = areaW / maxSeries .value ;
11581186 const idx = Math .floor (localX / slotW);
11591187
11601188 if (idx >= 0 && idx < maxSeries .value ) {
1161- if (hoveredIndex .value !== idx) {
1162- hoveredIndex .value = idx;
1163- toggleTooltipVisibility (true , idx);
1164- }
1189+ if (hoveredIndex .value !== idx) {
1190+ hoveredIndex .value = idx;
1191+ toggleTooltipVisibility (true , idx);
1192+ }
11651193 } else {
11661194 onSvgMouseLeave ();
11671195 }
@@ -1177,7 +1205,23 @@ function onSvgMouseLeave() {
11771205 toggleTooltipVisibility (false , null );
11781206}
11791207
1180- function onSvgClick () {
1208+ function onSvgClick (e ) {
1209+ const svgPt = clientToSvgCoords (e);
1210+ if (svgPt && svgRef .value ) {
1211+ const { left , right , top , bottom , width: areaW } = drawingArea .value ;
1212+
1213+ // Only react if click lands inside the drawing area
1214+ if (svgPt .x >= left && svgPt .x <= right && svgPt .y >= top && svgPt .y <= bottom) {
1215+ const slotW = areaW / Math .max (1 , maxSeries .value );
1216+ const idx = Math .floor ((svgPt .x - left) / slotW);
1217+
1218+ if (idx >= 0 && idx < maxSeries .value ) {
1219+ selectX (idx);
1220+ return ;
1221+ }
1222+ }
1223+ }
1224+
11811225 if (hoveredIndex .value != null ) {
11821226 selectX (hoveredIndex .value );
11831227 }
@@ -2955,7 +2999,7 @@ defineExpose({
29552999 : class = " `vue-ui-xy ${isFullscreen ? 'vue-data-ui-wrapper-fullscreen' : ''} ${FINAL_CONFIG.useCssAnimation ? '' : 'vue-ui-dna'}`"
29563000 ref= " chart"
29573001 : style= " `background:${FINAL_CONFIG.chart.backgroundColor}; color:${FINAL_CONFIG.chart.color};width:100%;font-family:${FINAL_CONFIG.chart.fontFamily};${FINAL_CONFIG.responsive ? 'height: 100%' : ''}`"
2958- @mouseenter= " () => setUserOptionsVisibility(true)" @mouseleave= " () => setUserOptionsVisibility(false)" >
3002+ @mouseenter= " () => setUserOptionsVisibility(true)" @mouseleave= " () => setUserOptionsVisibility(false)" @click = " onSvgClick " >
29593003 < PenAndPaper v- if = " FINAL_CONFIG.chart.userOptions.buttons.annotator && svgRef" : svgRef= " svgRef"
29603004 : backgroundColor= " FINAL_CONFIG.chart.backgroundColor" : color= " FINAL_CONFIG.chart.color"
29613005 : active= " isAnnotator" @close= " toggleAnnotator" / >
0 commit comments