import { ACTION_CROP, ACTION_ZOOM, CLASS_CROP, CLASS_MODAL, DATA_ACTION, DRAG_MODE_CROP, DRAG_MODE_MOVE, DRAG_MODE_NONE, EVENT_CROP_END, EVENT_CROP_MOVE, EVENT_CROP_START, REGEXP_ACTIONS, } from './constants'; import { addClass, assign, dispatchEvent, forEach, getData, getPointer, hasClass, isNumber, toggleClass, } from './utilities'; export default { resize() { if (this.disabled) { return; } const { options, container, containerData } = this; const ratio = container.offsetWidth / containerData.width; // Resize when width changed or height changed if (ratio !== 1 || container.offsetHeight !== containerData.height) { let canvasData; let cropBoxData; if (options.restore) { canvasData = this.getCanvasData(); cropBoxData = this.getCropBoxData(); } this.render(); if (options.restore) { this.setCanvasData(forEach(canvasData, (n, i) => { canvasData[i] = n * ratio; })); this.setCropBoxData(forEach(cropBoxData, (n, i) => { cropBoxData[i] = n * ratio; })); } } }, dblclick() { if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { return; } this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); }, wheel(event) { const ratio = Number(this.options.wheelZoomRatio) || 0.1; let delta = 1; if (this.disabled) { return; } event.preventDefault(); // Limit wheel speed to prevent zoom too fast (#21) if (this.wheeling) { return; } this.wheeling = true; setTimeout(() => { this.wheeling = false; }, 50); if (event.deltaY) { delta = event.deltaY > 0 ? 1 : -1; } else if (event.wheelDelta) { delta = -event.wheelDelta / 120; } else if (event.detail) { delta = event.detail > 0 ? 1 : -1; } this.zoom(-delta * ratio, event); }, cropStart(event) { const { buttons, button } = event; if ( this.disabled // Handle mouse event and pointer event and ignore touch event || (( event.type === 'mousedown' || (event.type === 'pointerdown' && event.pointerType === 'mouse') ) && ( // No primary button (Usually the left button) (isNumber(buttons) && buttons !== 1) || (isNumber(button) && button !== 0) // Open context menu || event.ctrlKey )) ) { return; } const { options, pointers } = this; let action; if (event.changedTouches) { // Handle touch event forEach(event.changedTouches, (touch) => { pointers[touch.identifier] = getPointer(touch); }); } else { // Handle mouse event and pointer event pointers[event.pointerId || 0] = getPointer(event); } if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { action = ACTION_ZOOM; } else { action = getData(event.target, DATA_ACTION); } if (!REGEXP_ACTIONS.test(action)) { return; } if (dispatchEvent(this.element, EVENT_CROP_START, { originalEvent: event, action, }) === false) { return; } // This line is required for preventing page zooming in iOS browsers event.preventDefault(); this.action = action; this.cropping = false; if (action === ACTION_CROP) { this.cropping = true; addClass(this.dragBox, CLASS_MODAL); } }, cropMove(event) { const { action } = this; if (this.disabled || !action) { return; } const { pointers } = this; event.preventDefault(); if (dispatchEvent(this.element, EVENT_CROP_MOVE, { originalEvent: event, action, }) === false) { return; } if (event.changedTouches) { forEach(event.changedTouches, (touch) => { // The first parameter should not be undefined (#432) assign(pointers[touch.identifier] || {}, getPointer(touch, true)); }); } else { assign(pointers[event.pointerId || 0] || {}, getPointer(event, true)); } this.change(event); }, cropEnd(event) { if (this.disabled) { return; } const { action, pointers } = this; if (event.changedTouches) { forEach(event.changedTouches, (touch) => { delete pointers[touch.identifier]; }); } else { delete pointers[event.pointerId || 0]; } if (!action) { return; } event.preventDefault(); if (!Object.keys(pointers).length) { this.action = ''; } if (this.cropping) { this.cropping = false; toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); } dispatchEvent(this.element, EVENT_CROP_END, { originalEvent: event, action, }); }, };