123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import BaseFoundation, { DefaultAdapter } from "../base/foundation";
- import { handlePrevent } from "../utils/a11y";
- import { throttle, isUndefined } from "lodash";
- export interface PreviewImageAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
- getOriginImageSize: () => { originImageWidth: number; originImageHeight: number };
- setOriginImageSize: (size: { originImageWidth: number; originImageHeight: number }) => void;
- getContainer: () => HTMLDivElement;
- getImage: () => HTMLImageElement;
- getMouseMove: () => boolean;
- setStartMouseMove: (move: boolean) => void;
- getMouseOffset: () => { x: number; y: number };
- setStartMouseOffset: (offset: { x: number; y: number }) => void;
- setLoading: (loading: boolean) => void;
- setImageCursor: (canDrag: boolean) => void
- }
- export interface DragDirection {
- canDragVertical: boolean;
- canDragHorizontal: boolean
- }
- export interface ExtremeBounds {
- left: number;
- top: number
- }
- export interface ImageOffset {
- x: number;
- y: number
- }
- const DefaultDOMRect = {
- bottom: 0,
- height: 0,
- left: 0,
- right: 0,
- top: 0,
- width: 0,
- x: 0,
- y: 0,
- toJSON: () => ({})
- };
- export default class PreviewImageFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<PreviewImageAdapter<P, S>, P, S> {
- constructor(adapter: PreviewImageAdapter<P, S>) {
- super({ ...adapter });
- }
- _isImageVertical = (): boolean => this.getProp("rotation") % 180 !== 0;
- _getImageBounds = (): DOMRect => {
- const imageDOM = this._adapter.getImage();
- if (imageDOM) {
- return imageDOM.getBoundingClientRect();
- }
- return DefaultDOMRect;
- };
- _getContainerBounds = (): DOMRect => {
- const containerDOM = this._adapter.getContainer();
- if (containerDOM) {
- return containerDOM.getBoundingClientRect();
- }
- return DefaultDOMRect;
- }
- _getOffset = (e: any): ImageOffset => {
- const { left, top } = this._getImageBounds();
- return {
- x: e.clientX - left,
- y: e.clientY - top,
- };
- }
- setLoading = (loading: boolean) => {
- this._adapter.setLoading(loading);
- }
- handleWindowResize = (): void => {
- const { setRatio } = this.getProps();
- const { ratio } = this.getProps();
- const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
- if (originImageWidth && originImageHeight) {
- if (ratio !== "adaptation") {
- setRatio("adaptation");
- } else {
- this.handleResizeImage();
- }
- }
- };
- handleLoad = (e: any): void => {
- if (e.target) {
- const { width: w, height: h } = e.target as any;
- this._adapter.setOriginImageSize({ originImageWidth: w, originImageHeight: h });
- this.setState({
- loading: false,
- } as any);
- this.handleResizeImage();
- }
- const { src, onLoad } = this.getProps();
- onLoad && onLoad(src);
- }
- handleError = (e: any): void => {
- const { onError, src } = this.getProps();
- this.setState({
- loading: false,
- } as any);
- onError && onError(src);
- }
- handleResizeImage = () => {
- const horizontal = !this._isImageVertical();
- const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
- const imgWidth = horizontal ? originImageWidth : originImageHeight;
- const imgHeight = horizontal ? originImageHeight : originImageWidth;
- const { onZoom } = this.getProps();
- const containerDOM = this._adapter.getContainer();
- if (containerDOM) {
- const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
- const reservedWidth = containerWidth - 80;
- const reservedHeight = containerHeight - 80;
- const _zoom = Number(
- Math.min(reservedWidth / imgWidth, reservedHeight / imgHeight).toFixed(2)
- );
- onZoom(_zoom);
- }
- }
- handleRightClickImage = (e: any) => {
- const { disableDownload } = this.getProps();
- if (disableDownload) {
- e.preventDefault();
- e.stopPropagation();
- return false;
- } else {
- return true;
- }
- };
- // e: WheelEvent<HTMLImageElement>
- handleWheel = (e: any) => {
- this.onWheel(e);
- handlePrevent(e);
- }
- // e: WheelEvent<HTMLImageElement>
- onWheel = throttle((e: any): void => {
- const { onZoom, zoomStep, maxZoom, minZoom } = this.getProps();
- const { currZoom } = this.getStates();
- let _zoom:number;
- if (e.deltaY < 0) {
- /* zoom in */
- if (currZoom + zoomStep <= maxZoom) {
- _zoom = Number((currZoom + zoomStep).toFixed(2));
- }
- } else if (e.deltaY > 0) {
- /* zoom out */
- if (currZoom - zoomStep >= minZoom) {
- _zoom = Number((currZoom - zoomStep).toFixed(2));
- }
- }
- if (!isUndefined(_zoom)) {
- onZoom(_zoom);
- }
- }, 50);
- calcCanDragDirection = (): DragDirection => {
- const { width, height } = this.getStates();
- const { rotation } = this.getProps();
- const { width: containerWidth, height: containerHeight } =this._getContainerBounds();
- let canDragHorizontal = width > containerWidth;
- let canDragVertical = height > containerHeight;
- if (this._isImageVertical()) {
- canDragHorizontal = height > containerWidth;
- canDragVertical = width > containerHeight;
- }
- return {
- canDragVertical,
- canDragHorizontal,
- };
- };
- handleZoomChange = (newZoom: number, e: any): void => {
- const imageDOM = this._adapter.getImage();
- const { originImageWidth, originImageHeight } = this._adapter.getOriginImageSize();
- const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
- const canDrag = canDragVertical || canDragHorizontal;
- const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
- const newWidth = Math.floor(originImageWidth * newZoom);
- const newHeight = Math.floor(originImageHeight * newZoom);
- // debugger;
- let _offset;
- const horizontal = !this._isImageVertical();
- let newTop = 0;
- let newLeft = 0;
- if (horizontal) {
- _offset = {
- x: 0.5 * (containerWidth - newWidth),
- y: 0.5 * (containerHeight - newHeight),
- };
-
- newLeft = _offset.x;
- newTop= _offset.y;
- } else {
- _offset = {
- x: 0.5 * (containerWidth - newHeight),
- y: 0.5 * (containerHeight - newWidth),
- };
- newLeft = _offset.x - (newWidth - newHeight) / 2;
- newTop = _offset.y + (newWidth - newHeight) / 2;
- }
-
- this.setState({
- width: newWidth,
- height: newHeight,
- offset: _offset,
- left: newLeft,
- top: newTop,
- currZoom: newZoom,
- } as any);
- if (imageDOM) {
- this._adapter.setImageCursor(canDrag);
- }
- };
- calcExtremeBounds = (): ExtremeBounds => {
- const { width, height } = this.getStates();
- const { width: containerWidth, height: containerHeight } = this._getContainerBounds();
- let extremeLeft = containerWidth - width;
- let extremeTop = containerHeight - height;
- if (this._isImageVertical()) {
- extremeLeft = containerWidth - height;
- extremeTop = containerHeight - width;
- }
- return {
- left: extremeLeft,
- top: extremeTop,
- };
- };
- handleMoveImage = (e: any): void => {
- const { offset, width, height } = this.getStates();
- const startMouseMove = this._adapter.getMouseMove();
- const startMouseOffset = this._adapter.getMouseOffset();
- const { canDragVertical, canDragHorizontal } = this.calcCanDragDirection();
- if (startMouseMove && (canDragVertical || canDragHorizontal)) {
- const { clientX, clientY } = e;
- const { left: containerLeft, top: containerTop } = this._getContainerBounds();
- const { left: extremeLeft, top: extremeTop } = this.calcExtremeBounds();
- let newX = canDragHorizontal ? clientX - containerLeft - startMouseOffset.x : offset.x;
- let newY = canDragVertical ? clientY - containerTop - startMouseOffset.y : offset.y;
- if (canDragHorizontal) {
- newX = newX > 0 ? 0 : newX < extremeLeft ? extremeLeft : newX;
- }
- if (canDragVertical) {
- newY = newY > 0 ? 0 : newY < extremeTop ? extremeTop : newY;
- }
- const _offset = {
- x: newX,
- y: newY,
- };
- this.setState({
- offset: _offset,
- left: this._isImageVertical() ? _offset.x - (width - height) / 2 : _offset.x,
- top: this._isImageVertical() ? _offset.y + (width - height) / 2 : _offset.y,
- } as any);
- }
- };
- handleImageMouseDown = (e: any): void => {
- this._adapter.setStartMouseOffset(this._getOffset(e));
- this._adapter.setStartMouseMove(true);
- };
- handleImageMouseUp = (): void => {
- this._adapter.setStartMouseMove(false);
- };
- }
|