UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

187 lines (176 loc) 5.41 kB
import type { TMat2D, FabricObject, TransformActionHandler, Control, ControlRenderingStyleOverride, InteractiveFabricObject, Gradient, } from 'fabric'; import { Point, util, controlsUtils, iMatrix } from 'fabric'; /** A deduping code block */ const commonGradientInfo = ( fabricObject: FabricObject, gradient: Gradient<'linear'>, ) => { const { width, height } = fabricObject; const { colorStops, coords, gradientUnits } = gradient; const isPerc = gradientUnits === 'percentage'; const matrix = fabricObject.calcTransformMatrix(); const vpt = fabricObject.getViewportTransform(); const _finalMatrix = util.multiplyTransformMatrixArray([vpt, matrix]); return { width, height, colorStops, coords, isPerc, _finalMatrix, }; }; export const linearGradientColorPositionHandlerGenerator = ( gradient: Gradient<'linear'>, stopIndex: number, ) => function linearGradientColorPositionHandler( this: Control, dim: Point, // currentDimension finalMatrix: TMat2D, fabricObject: FabricObject, // currentControl: Control,) => {}; ) { const { width, height, isPerc, coords, colorStops, _finalMatrix } = commonGradientInfo(fabricObject, gradient); const p1 = new Point( coords.x1 * (isPerc ? width : 1) - width / 2, coords.y1 * (isPerc ? height : 1) - height / 2, ); const p2 = new Point( coords.x2 * (isPerc ? width : 1) - width / 2, coords.y2 * (isPerc ? height : 1) - height / 2, ); const offset = colorStops[stopIndex].offset; return p1.lerp(p2, offset).transform(_finalMatrix); }; export const linearGradientCoordPositionHandlerGenerator = ( gradient: Gradient<'linear'>, pointNumber: 1 | 2, ) => function linearGradientCoordPositionHandler( this: Control, dim: Point, // currentDimension finalMatrix: TMat2D, fabricObject: FabricObject, // currentControl: Control,) => {}; ) { const { width, height, isPerc, coords, _finalMatrix } = commonGradientInfo( fabricObject, gradient, ); return ( pointNumber === 1 ? new Point( coords.x1 * (isPerc ? width : 1) - width / 2, coords.y1 * (isPerc ? height : 1) - height / 2, ) : new Point( coords.x2 * (isPerc ? width : 1) - width / 2, coords.y2 * (isPerc ? height : 1) - height / 2, ) ).transform(_finalMatrix); }; export const linearGradientColorActionHandlerGenerator = (gradient: Gradient<'linear'>, colorIndex: number): TransformActionHandler => (eventData, { target }, x, y) => { const { width, height, isPerc, coords: { x1, x2, y1, y2 }, colorStops, } = commonGradientInfo(target, gradient); // find point in the space inside the object. const point = util .sendPointToPlane( new Point(x, y), undefined, target.calcTransformMatrix(), ) .add(new Point(width / 2, height / 2)); const p1 = new Point(x1 * (isPerc ? width : 1), y1 * (isPerc ? height : 1)); const v = util.createVector( p1, new Point(x2 * (isPerc ? width : 1), y2 * (isPerc ? height : 1)), ); const u = util.createVector(p1, point); const t = util.dotProduct(u, v) / util.dotProduct(v, v); colorStops[colorIndex].offset = util.capValue(0, t, 1); target.set('dirty', true); return true; }; export const linearGradientCoordsActionHandlerGenerator = (gradient: Gradient<'linear'>, pointIndex: 1 | 2): TransformActionHandler => (eventData, { target }, x, y) => { const { width, height, isPerc, coords } = commonGradientInfo( target, gradient, ); // find point in the space inside the object. const point = util .sendPointToPlane( new Point(x, y), undefined, target.calcTransformMatrix(), ) .add(new Point(width / 2, height / 2)); if (pointIndex === 1) { coords.x1 = point.x / (isPerc ? width : 1); coords.y1 = point.y / (isPerc ? height : 1); } if (pointIndex === 2) { coords.x2 = point.x / (isPerc ? width : 1); coords.y2 = point.y / (isPerc ? height : 1); } target.set('dirty', true); return true; }; export const linearGradientControlLineRender = (gradient: Gradient<'linear'>) => function renderCircleControlWithLine( this: Control, ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride, fabricObject: InteractiveFabricObject, ) { // we are position in center of coords.x1/y1 ctx.save(); const { width, height, isPerc, coords } = commonGradientInfo( fabricObject as FabricObject, gradient, ); const finalP = util.sendPointToPlane( new Point( coords.x2 * (isPerc ? width : 1) - width / 2, coords.y2 * (isPerc ? height : 1) - height / 2, ), util.multiplyTransformMatrices( fabricObject.canvas?.viewportTransform ?? iMatrix, fabricObject.calcTransformMatrix(), ), ); ctx.lineWidth = fabricObject.borderScaleFactor; ctx.beginPath(); ctx.moveTo(left, top); ctx.lineTo(finalP.x, finalP.y); ctx.stroke(); controlsUtils.renderCircleControl.call( this, ctx, left, top, styleOverride, fabricObject, ); ctx.restore(); };