lets-plot-compose/src/androidMain/kotlin/org/jetbrains/letsPlot/compose/PlotPanelComposeCanvas.kt [249:295]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private var clickCount: Int = 0 private var lastClickTime: Long = 0 private var offsetX: Float = 0f private var offsetY: Float = 0f fun setOffset(offsetX: Float, offsetY: Float) { this.offsetX = offsetX this.offsetY = offsetY } override fun addEventHandler(eventSpec: MouseEventSpec, eventHandler: EventHandler): Registration { return mouseEventPeer.addEventHandler(eventSpec, eventHandler) } override suspend fun PointerInputScope.invoke() { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() val change = event.changes.first() val position = change.position // Convert logical pixel coordinates to physical pixel coordinates for SVG interaction // 1. Scale down by density (logical → physical pixels) // 2. Subtract position offset (which is also in physical pixels) val adjustedX = ((position.x / density) - offsetX).roundToInt() val adjustedY = ((position.y / density) - offsetY).roundToInt() val vector = Vector(adjustedX, adjustedY) val mouseEvent = when { change.pressed -> MouseEvent.leftButton(vector) else -> MouseEvent.noButton(vector) } when (event.type) { PointerEventType.Press -> { val currentTime = System.currentTimeMillis() clickCount = if (currentTime - lastClickTime < 300) { clickCount + 1 } else { 1 } lastClickTime = currentTime mouseEventPeer.dispatch(MOUSE_PRESSED, mouseEvent) } PointerEventType.Release -> { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lets-plot-compose/src/desktopMain/kotlin/org/jetbrains/letsPlot/compose/ComposeMouseEventMapper.kt [16:62]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private var clickCount: Int = 0 private var lastClickTime: Long = 0 private var offsetX: Float = 0f private var offsetY: Float = 0f fun setOffset(offsetX: Float, offsetY: Float) { this.offsetX = offsetX this.offsetY = offsetY } override fun addEventHandler(eventSpec: MouseEventSpec, eventHandler: EventHandler): Registration { return mouseEventPeer.addEventHandler(eventSpec, eventHandler) } override suspend fun PointerInputScope.invoke() { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() val change = event.changes.first() val position = change.position // Convert logical pixel coordinates to physical pixel coordinates for SVG interaction // 1. Scale down by density (logical → physical pixels) // 2. Subtract position offset (which is also in physical pixels) val adjustedX = ((position.x / density) - offsetX).roundToInt() val adjustedY = ((position.y / density) - offsetY).roundToInt() val vector = Vector(adjustedX, adjustedY) val mouseEvent = when { change.pressed -> MouseEvent.leftButton(vector) else -> MouseEvent.noButton(vector) } when (event.type) { PointerEventType.Press -> { val currentTime = System.currentTimeMillis() clickCount = if (currentTime - lastClickTime < 300) { clickCount + 1 } else { 1 } lastClickTime = currentTime mouseEventPeer.dispatch(MOUSE_PRESSED, mouseEvent) } PointerEventType.Release -> { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -