import type { PointerEventState } from '@blockeditor/block-std'; import { assertExists } from '@blockeditor/global/utils'; import { type BlockComponent, getClosestBlockElementByElement, getModelByElement, isEdgelessPage, } from '../_common/utils/query.js'; import { getClosestPageBlockComponent } from '../page-block/utils/query.js'; export class ImageResizeManager { private _activeComponent: BlockComponent | null = null; private _imageContainer: HTMLElement | null = null; private _imageCenterX = 0; private _dragMoveTarget = 'right'; private _zoom = 1; onStart(e: PointerEventState) { const eventTarget = e.raw.target as HTMLElement; this._activeComponent = getClosestBlockElementByElement( eventTarget ) as BlockComponent; const pageElement = getClosestPageBlockComponent(this._activeComponent); if (pageElement && isEdgelessPage(pageElement)) { this._zoom = pageElement.service.viewport.zoom; } else { this._zoom = 1; } this._imageContainer = eventTarget.closest('.resizable-img'); assertExists(this._imageContainer); const rect = this._imageContainer.getBoundingClientRect() as DOMRect; this._imageCenterX = rect.left + rect.width / 2; if (eventTarget.className.includes('right')) { this._dragMoveTarget = 'right'; } else { this._dragMoveTarget = 'left'; } } onMove(e: PointerEventState) { assertExists(this._activeComponent); const activeComponent = this._activeComponent; const activeImgContainer = this._imageContainer; assertExists(activeImgContainer); const activeImg = activeComponent.querySelector('img'); assertExists(activeImg); let width = 0; if (this._dragMoveTarget === 'right') { width = (e.raw.pageX - this._imageCenterX) * 2; } else { width = (this._imageCenterX - e.raw.pageX) * 2; } const MIN_WIDTH = 50; if (width < MIN_WIDTH) { width = MIN_WIDTH; } if (width > activeComponent.getBoundingClientRect().width) { width = activeComponent.getBoundingClientRect().width; } const height = width * (activeImg.naturalHeight / activeImg.naturalWidth); const containerRect = activeImgContainer.getBoundingClientRect(); if (containerRect.width === width && containerRect.height === height) return; requestAnimationFrame(() => { activeImgContainer.style.width = (width / this._zoom).toFixed(2) + 'px'; activeImgContainer.style.height = (height / this._zoom).toFixed(2) + 'px'; }); } onEnd() { assertExists(this._activeComponent); assertExists(this._imageContainer); const dragModel = getModelByElement(this._activeComponent); dragModel.page.captureSync(); const { width, height } = this._imageContainer.getBoundingClientRect(); dragModel.page.updateBlock(dragModel, { width: width / this._zoom, height: height / this._zoom, }); } }