import React, { useCallback, useContext, useEffect, useRef } from 'react'; import { fabric } from 'fabric'; import { FabricTexture, AbstractMode, Texture } from 'fabric-texture'; import Warp from 'fabric-texture/modes/warp'; import { Canvas } from 'docs/components'; import type { CanvasHandlers } from 'docs/components/canvas'; import { DocsContext } from 'docs/docs'; import styles from './style.less'; import { calcFabricCanvasCoord, calcCoordDistance, calcRelativeCoord, calcFabricRelativeCoord, } from '@utils'; export class ConvexMode extends AbstractMode { name = 'convex'; convexCenterPoint: Coord | null = null; constructor( public radius: number, public level: number, ) { super(); } execute(texture: Texture) { const points = Warp.execute(texture); const centerPoint = this.convexCenterPoint; if (!centerPoint) return points; return points.map((rows) => rows.map((row) => row.map((point) => { const distance = calcCoordDistance(centerPoint, point); if (distance <= this.radius) { return calcRelativeCoord( centerPoint, point, this.radius - this.radius * (1 - distance / this.radius) ** Math.max(0, this.level), ); } else { return point; } }), ), ); } dirtyRender(fabricTexture: FabricTexture) { const fabricCanvas = fabricTexture.canvas; if (!fabricCanvas) return; fabricCanvas.on('mouse:move', (e) => { if (!e.pointer) return; const pointer = calcFabricCanvasCoord(fabricCanvas, e.pointer); const path = fabricTexture.paths?.[0]; if (!path) return; const coord = calcFabricRelativeCoord({ left: pointer.x, top: pointer.y }, path); this.convexCenterPoint = coord; fabricTexture.requestRender(false); }); } } const Customization = () => { const { placeholder } = useContext(DocsContext); const _canvasRef = useRef(null); const _fabricTextureRef = useRef(); const render = useCallback(async () => { const canvas = _canvasRef.current?.getCanvas(); if (!canvas) return; const width = canvas.getWidth(); const height = canvas.getHeight(); if (!placeholder) return; // 限制画布不允许多选 canvas.selection = false; // 缩放以控制在合理渲染区域内 const scale = Math.min(200, canvas.getWidth()) / Math.min(placeholder.naturalWidth, placeholder.naturalHeight); // 创建元素 const object = new fabric.Image(placeholder, { left: width / 2, top: height / 2, scaleX: scale, scaleY: scale, originX: 'center', originY: 'center', }); // 进入交互态 const fabricTexture = new FabricTexture(canvas); fabricTexture.enterEditing(object, null, new ConvexMode(100, 3)); if (_fabricTextureRef.current) { _fabricTextureRef.current.leaveEditing(); } _fabricTextureRef.current = fabricTexture; fabricTexture.texture?.setSplitUnit(0.02).useInstanceCanvas().setRenderOptions({ padding: 60 }); fabricTexture.render(); // 隐藏源元素 object.set({ visible: false }); canvas.renderAll(); }, [placeholder]); useEffect(() => { render(); }, [render]); return (
移动鼠标到图案上
); }; export default Customization;