1- import React from "react" ;
1+ import React , { useCallback , useRef } from "react" ;
22import bwipjs from "bwip-js/browser" ;
33import { Image as KImage , Group , Rect , Text } from "react-konva" ;
44import type Konva from "konva" ;
@@ -43,6 +43,20 @@ export function BarcodeObject({
4343 onChange,
4444 snap,
4545} : Props ) {
46+ const groupRef = useRef < Konva . Group > ( null ) ;
47+ const textRef = useRef < Konva . Text > ( null ) ;
48+
49+ // Exclude the HRI text from the parent Group's getClientRect. This anchors
50+ // the resize at the bar top (logmars: was anchoring at text top above bars)
51+ // and keeps the Transformer's bbox tight around the bars, eliminating the
52+ // (h + textArea)*sy vs h*sy + textArea discrepancy during drag.
53+ const setTextRef = useCallback ( ( node : Konva . Text | null ) => {
54+ textRef . current = node ;
55+ if ( node ) {
56+ node . getSelfRect = ( ) => ( { x : 0 , y : 0 , width : 0 , height : 0 } ) ;
57+ }
58+ } , [ ] ) ;
59+
4660 const opts = buildBwipOptions ( obj , scale , dpmm ) ;
4761 let barcodeCanvas : HTMLCanvasElement | null = null ;
4862 let errorMsg : string | null = null ;
@@ -413,6 +427,7 @@ export function BarcodeObject({
413427 imageSmoothingEnabled = { false }
414428 stroke = { isSelected ? "#6366f1" : undefined }
415429 strokeWidth = { isSelected ? 2 : 0 }
430+ strokeScaleEnabled = { false }
416431 />
417432 { textNodes }
418433 </ Group >
@@ -445,19 +460,43 @@ export function BarcodeObject({
445460 const aboveGap = isTextAbove
446461 ? Math . max ( dotsToPx ( LOGMARS_TEXT_ABOVE_GAP_DOTS , scale , dpmm ) , 3 )
447462 : textGap ;
448- const txtY = isTextAbove ? - ( textFontSize + aboveGap ) : Math . max ( h , 1 ) + textGap ;
449- const clipY = isTextAbove ? - ( textFontSize + aboveGap ) : 0 ;
450- const clipHeight = Math . max ( h , 1 ) + textFontSize + aboveGap ;
463+ // Local y for the HRI text. The /sy form keeps a constant *visual* offset
464+ // when the group is being scaled (sy = 1 at rest, ≠ 1 during a drag).
465+ const textLocalY = ( sy : number ) =>
466+ isTextAbove
467+ ? - ( textFontSize + aboveGap ) / sy
468+ : Math . max ( h , 1 ) + textGap / sy ;
469+ const txtY = textLocalY ( 1 ) ;
470+
471+ // Counter-scale the text so it stays at constant pixel size while the
472+ // bars stretch with the parent group's scaleY during a resize drag.
473+ const handleTransform = ( ) => {
474+ const grp = groupRef . current ;
475+ const txt = textRef . current ;
476+ if ( ! grp || ! txt ) return ;
477+ const sy = grp . scaleY ( ) ;
478+ if ( sy <= 0 ) return ;
479+ txt . scaleY ( 1 / sy ) ;
480+ txt . y ( textLocalY ( sy ) ) ;
481+ } ;
482+
483+ // react-konva does not track imperatively-set scaleY/y. Reset both here
484+ // so the next drag starts clean. For logmars the JSX y is constant, so
485+ // without an explicit reset react-konva would not re-apply it on the
486+ // post-commit render and the text would stay at its last drag-time y.
487+ const handleTransformEnd = ( ) => {
488+ const txt = textRef . current ;
489+ if ( ! txt ) return ;
490+ txt . scaleY ( 1 ) ;
491+ txt . y ( txtY ) ;
492+ } ;
451493
452494 return (
453495 < Group
496+ ref = { groupRef }
454497 id = { obj . id }
455498 x = { x }
456499 y = { y }
457- clipX = { 0 }
458- clipY = { clipY }
459- clipWidth = { Math . max ( w , 1 ) }
460- clipHeight = { clipHeight }
461500 draggable
462501 onClick = { ( e ) =>
463502 onSelect ( e . evt . shiftKey || e . evt . ctrlKey || e . evt . metaKey )
@@ -467,6 +506,8 @@ export function BarcodeObject({
467506 e . target . position ( snapPos ( e . target . x ( ) , e . target . y ( ) ) )
468507 }
469508 onDragEnd = { handleDragEnd }
509+ onTransform = { handleTransform }
510+ onTransformEnd = { handleTransformEnd }
470511 >
471512 < KImage
472513 x = { 0 }
@@ -477,8 +518,10 @@ export function BarcodeObject({
477518 imageSmoothingEnabled = { false }
478519 stroke = { isSelected ? "#6366f1" : undefined }
479520 strokeWidth = { isSelected ? 2 : 0 }
521+ strokeScaleEnabled = { false }
480522 />
481523 < Text
524+ ref = { setTextRef }
482525 x = { 0 }
483526 y = { txtY }
484527 width = { Math . max ( w , 1 ) }
@@ -505,6 +548,7 @@ export function BarcodeObject({
505548 imageSmoothingEnabled = { false }
506549 stroke = { isSelected ? "#6366f1" : undefined }
507550 strokeWidth = { isSelected ? 2 : 0 }
551+ strokeScaleEnabled = { false }
508552 draggable
509553 onClick = { ( e ) =>
510554 onSelect ( e . evt . shiftKey || e . evt . ctrlKey || e . evt . metaKey )
0 commit comments