91 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| export const zoom = function(superClass) {
 | |
|   return class extends superClass {
 | |
|     static get properties() {
 | |
|       return {
 | |
|         scale: { type: Number }
 | |
|       };
 | |
|     }
 | |
| 
 | |
|     constructor() {
 | |
|       super();
 | |
|       this.scale = 1;
 | |
|       this._handleWheel = this._handleWheel.bind(this);
 | |
|       this.MIN_SCALE = 0.1;
 | |
|       this.MAX_SCALE = 1.0;
 | |
|       this.SCALE_STEP = 0.1;
 | |
|     }
 | |
| 
 | |
|     firstUpdated() {
 | |
|       super.firstUpdated();
 | |
|       this.canvas = this.shadowRoot.querySelector('.canvas');
 | |
|       this.addEventListener('wheel', this._handleWheel, { passive: false });
 | |
|     }
 | |
| 
 | |
|     _handleWheel(e) {
 | |
|       e.preventDefault();
 | |
|       
 | |
|       if (e.deltaY > 0) {
 | |
|         this.zoomOut();
 | |
|       } else if (e.deltaY < 0) {
 | |
|         this.zoomIn();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Zooms out the canvas by one step
 | |
|      * @returns {boolean} True if zoom was applied, false if already at minimum
 | |
|      */
 | |
|     zoomOut() {
 | |
|       const newScale = Math.max(this.MIN_SCALE, this.scale - this.SCALE_STEP);
 | |
|       if (newScale !== this.scale) {
 | |
|         this._applyZoom(newScale);
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Zooms in the canvas by one step
 | |
|      * @returns {boolean} True if zoom was applied, false if already at maximum
 | |
|      */
 | |
|     zoomIn() {
 | |
|       const newScale = Math.min(this.MAX_SCALE, this.scale + this.SCALE_STEP);
 | |
|       if (newScale !== this.scale) {
 | |
|         this._applyZoom(newScale);
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Immediately resets zoom to 100%
 | |
|      */
 | |
|     resetZoom() {
 | |
|       this._applyZoom(this.MAX_SCALE);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Applies the zoom scale to the canvas
 | |
|      * @private
 | |
|      */
 | |
|     _applyZoom(newScale) {
 | |
|       this.scale = newScale;
 | |
|       
 | |
|       // Get current translation
 | |
|       const transform = window.getComputedStyle(this.canvas).transform;
 | |
|       const matrix = new DOMMatrix(transform);
 | |
|       const currentX = matrix.m41;
 | |
|       const currentY = matrix.m42;
 | |
|     
 | |
|       // Apply both transforms
 | |
|       this.canvas.style.transform = `translate(${currentX}px, ${currentY}px) scale(${this.scale})`;
 | |
|       this.canvas.style.transformOrigin = 'center center';
 | |
|       this.requestUpdate();
 | |
|     }
 | |
| 
 | |
|     disconnectedCallback() {
 | |
|       super.disconnectedCallback();
 | |
|       this.removeEventListener('wheel', this._handleWheel);
 | |
|     }
 | |
|   };
 | |
| } |