@@ -420,20 +420,18 @@ export default function startListeners() {
420420 }
421421
422422 // Keyboard zoom shortcuts
423- // Zoom in: Cmd/Ctrl + '+' or Cmd/Ctrl + '= '
424- // (On US keyboards, '+' is Shift+'=', so we accept both to handle with/without Shift)
425- // Also accepts keyCode 107 for numpad '+'
423+ // Zoom in: Cmd/Ctrl + '+' or numpad '+ '
424+ // (On US keyboards, '+' is Shift+'='; we only check for '+' to avoid
425+ // triggering on plain '=' which would require Cmd/Ctrl+Shift+= instead)
426426 if (
427427 ( simulationArea . controlDown &&
428- ( e . keyCode == 187 || e . keyCode == 171 || e . key == '+' || e . key == '=' ) ) ||
428+ ( e . keyCode == 187 || e . keyCode == 171 || e . key == '+' ) ) ||
429429 e . keyCode == 107
430430 ) {
431431 e . preventDefault ( )
432432 ZoomIn ( )
433433 }
434- // Zoom out: Cmd/Ctrl + '-'
435- // (Only '-', not '_', since '_' requires Shift and could cause confusion)
436- // Also accepts keyCode 109 for numpad '-'
434+ // Zoom out: Cmd/Ctrl + '-' or numpad '-'
437435 if (
438436 ( simulationArea . controlDown &&
439437 ( e . keyCode == 189 || e . keyCode == 173 || e . key == '-' ) ) ||
@@ -631,9 +629,9 @@ export default function startListeners() {
631629 */
632630 function applyCanvasPan ( deltaX , deltaY ) {
633631 // Pan the canvas by adjusting origin
634- // Invert delta: positive scroll should move content down/right
635- globalScope . ox - = deltaX
636- globalScope . oy - = deltaY
632+ // Positive scroll moves content down/right
633+ globalScope . ox + = deltaX
634+ globalScope . oy + = deltaY
637635
638636 // Round to avoid subpixel rendering issues
639637 globalScope . ox = Math . round ( globalScope . ox )
@@ -661,12 +659,10 @@ export default function startListeners() {
661659 }
662660
663661 // Register wheel/trackpad event listeners for canvas panning
664- document
665- . getElementById ( 'simulationArea' )
666- . addEventListener ( 'mousewheel' , handleCanvasPan )
667- document
668- . getElementById ( 'simulationArea' )
669- . addEventListener ( 'DOMMouseScroll' , handleCanvasPan )
662+ const simulationAreaElement = document . getElementById ( 'simulationArea' )
663+ simulationAreaElement . addEventListener ( 'wheel' , handleCanvasPan , { passive : false } )
664+ simulationAreaElement . addEventListener ( 'mousewheel' , handleCanvasPan , { passive : false } )
665+ simulationAreaElement . addEventListener ( 'DOMMouseScroll' , handleCanvasPan , { passive : false } )
670666
671667 document . addEventListener ( 'cut' , ( e ) => {
672668 if ( verilogModeGet ( ) ) return
@@ -807,11 +803,13 @@ resizeTabs()
807803 */
808804function applyZoomChange ( direction ) {
809805 const zoomDelta = direction * 0.1 * DPR
810- const newScale = globalScope . scale + zoomDelta
811-
812- // Ensure scale stays within valid bounds
813- if ( newScale >= 0.5 * DPR && newScale <= 4 * DPR ) {
814- changeScale ( zoomDelta )
806+ const targetScale = Math . max (
807+ 0.5 * DPR ,
808+ Math . min ( 4 * DPR , globalScope . scale + zoomDelta )
809+ )
810+
811+ if ( targetScale !== globalScope . scale ) {
812+ changeScale ( targetScale - globalScope . scale )
815813 gridUpdateSet ( true )
816814 scheduleUpdate ( )
817815 }
@@ -853,6 +851,8 @@ export function setZoomFromSlider(
853851 minZoom = 0.5 * DPR ,
854852 maxZoom = 4 * DPR
855853) {
854+ if ( maxSliderValue === minSliderValue || maxZoom === minZoom ) return
855+
856856 // Normalize slider value to 0-1 range
857857 const normalizedValue = ( sliderValue - minSliderValue ) / ( maxSliderValue - minSliderValue )
858858
@@ -893,6 +893,10 @@ export function getZoomSliderValue(
893893 minZoom = 0.5 * DPR ,
894894 maxZoom = 4 * DPR
895895) {
896+ if ( maxSliderValue === minSliderValue || maxZoom === minZoom ) {
897+ return minSliderValue
898+ }
899+
896900 const currentScale = globalScope . scale
897901
898902 // Clamp current scale to valid range
0 commit comments