UNPKG

fabric

Version:

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

224 lines (217 loc) 9.47 kB
import { defineProperty as _defineProperty } from '../_virtual/_rollupPluginBabelHelpers.mjs'; import { util } from 'fabric'; import { collectVerticalPoint, collectHorizontalPoint } from './util/collect-point.mjs'; import { drawLine, drawX, drawPointList, drawVerticalLine, drawHorizontalLine } from './util/draw.mjs'; import { collectLine } from './util/collect-line.mjs'; import { getObjectsByTarget } from './util/get-objects-by-target.mjs'; import { getPointMap, getContraryMap } from './util/basic.mjs'; class AligningGuidelines { constructor(canvas) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _defineProperty(this, "canvas", void 0); _defineProperty(this, "horizontalLines", new Set()); _defineProperty(this, "verticalLines", new Set()); _defineProperty(this, "cacheMap", new Map()); /** * When we drag to resize using center points like mt, ml, mb, and mr, * we do not need to draw line segments; we only need to draw the target points. */ _defineProperty(this, "onlyDrawPoint", false); /** Alignment method is required when customizing. */ _defineProperty(this, "contraryOriginMap", { tl: ['right', 'bottom'], tr: ['left', 'bottom'], br: ['left', 'top'], bl: ['right', 'top'], mt: ['center', 'bottom'], mr: ['left', 'center'], mb: ['center', 'top'], ml: ['right', 'center'] }); _defineProperty(this, "xSize", 2.4); _defineProperty(this, "lineDash", void 0); /** At what distance from the shape does alignment begin? */ _defineProperty(this, "margin", 4); /** Aligning line dimensions */ _defineProperty(this, "width", 1); /** Aligning line color */ _defineProperty(this, "color", 'rgba(255,0,0,0.9)'); /** Close Vertical line, default false. */ _defineProperty(this, "closeVLine", false); /** Close horizontal line, default false. */ _defineProperty(this, "closeHLine", false); this.canvas = canvas; Object.assign(this, options); this.mouseUp = this.mouseUp.bind(this); this.scalingOrResizing = this.scalingOrResizing.bind(this); this.moving = this.moving.bind(this); this.beforeRender = this.beforeRender.bind(this); this.afterRender = this.afterRender.bind(this); this.initBehavior(); } initBehavior() { this.canvas.on('mouse:up', this.mouseUp); this.canvas.on('object:resizing', this.scalingOrResizing); this.canvas.on('object:scaling', this.scalingOrResizing); this.canvas.on('object:moving', this.moving); this.canvas.on('before:render', this.beforeRender); this.canvas.on('after:render', this.afterRender); } /** Returns shapes that can draw aligning lines, default returns all shapes on the canvas excluding groups. */ getObjectsByTarget(target) { return getObjectsByTarget(target); } /** When the user customizes the controller, this property is set to enable or disable automatic alignment through point scaling/resizing. */ getPointMap(target) { return getPointMap(target); } /** When the user customizes the controller, this property is used to enable or disable alignment positioning through points. */ getContraryMap(target) { return getContraryMap(target); } /** Users can customize. */ getCaCheMapValue(object) { const cacheKey = [object.calcTransformMatrix().toString(), object.width, object.height].join(); const cacheValue = this.cacheMap.get(cacheKey); if (cacheValue) return cacheValue; const value = object.getCoords(); value.push(object.getCenterPoint()); this.cacheMap.set(cacheKey, value); return value; } drawLine(origin, target) { drawLine.call(this, origin, target); } drawX(point, dir) { drawX.call(this, point, dir); } mouseUp() { this.verticalLines.clear(); this.horizontalLines.clear(); this.cacheMap.clear(); this.canvas.requestRenderAll(); } scalingOrResizing(e) { const target = e.target; // We need to obtain the real-time coordinates of the current object, so we need to update them in real-time target.setCoords(); // The value of action can be scaleX, scaleY, scale, resize, etc. // If it does not start with "scale," it is considered a modification of size. const isScale = String(e.transform.action).startsWith('scale'); this.verticalLines.clear(); this.horizontalLines.clear(); const objects = this.getObjectsByTarget(target); // When the shape is flipped, the tl obtained through getCoords is actually tr, // and tl is actually tr. We need to make correction adjustments. // tr <-> tl、 bl <-> br、 mb <-> mt、 ml <-> mr let corner = e.transform.corner; if (target.flipX) { if (corner.includes('l')) corner = corner.replace('l', 'r');else if (corner.includes('r')) corner = corner.replace('r', 'l'); } if (target.flipY) { if (corner.includes('t')) corner = corner.replace('t', 'b');else if (corner.includes('b')) corner = corner.replace('b', 't'); } // Obtain the coordinates of the current operation point through the value of corner. // users can be allowed to customize and pass in custom corners. const pointMap = this.getPointMap(target); if (!(corner in pointMap)) return; this.onlyDrawPoint = corner.includes('m'); if (this.onlyDrawPoint) { const angle = target.getTotalAngle(); // When the shape is rotated, it is meaningless to draw points using the center point. if (angle % 90 != 0) return; } // If manipulating tl, then when the shape changes size, it should be positioned by br, // and the same applies to others. // users can be allowed to customize and pass in custom corners. const contraryMap = this.getContraryMap(target); const point = pointMap[corner]; let diagonalPoint = contraryMap[corner]; // When holding the centerKey (default is altKey), the shape will scale based on the center point, with the reference point being the center. const isCenter = e.transform.original.originX == 'center' && e.transform.original.originY == 'center'; if (isCenter) { const p = target.group ? point.transform(util.invertTransform(target.group.calcTransformMatrix())) : point; diagonalPoint = diagonalPoint.add(p).scalarDivide(2); } const uniformIsToggled = e.e[this.canvas.uniScaleKey]; let isUniform = this.canvas.uniformScaling && !uniformIsToggled || !this.canvas.uniformScaling && uniformIsToggled; // When controlling through the center point, // if isUniform is true, it actually changes the skew, so it is meaningless. if (this.onlyDrawPoint) isUniform = false; const list = []; for (const object of objects) { const d = this.getCaCheMapValue(object); list.push(...d); } const props = { target, point, diagonalPoint, corner, list, isScale, isUniform, isCenter }; // Obtain horizontal and vertical reference lines. const noNeedToCollectV = this.onlyDrawPoint && (corner.includes('t') || corner.includes('b')); const noNeedToCollectH = this.onlyDrawPoint && (corner.includes('l') || corner.includes('r')); const vList = noNeedToCollectV ? [] : collectVerticalPoint.call(this, props); const hList = noNeedToCollectH ? [] : collectHorizontalPoint.call(this, props); vList.forEach(o => { // Objects cannot be deduplicated; convert them to strings for deduplication. this.verticalLines.add(JSON.stringify(o)); }); hList.forEach(o => { // Objects cannot be deduplicated; convert them to strings for deduplication. this.horizontalLines.add(JSON.stringify(o)); }); } moving(e) { const target = e.target; // We need to obtain the real-time coordinates of the current object, so we need to update them in real-time target.setCoords(); this.onlyDrawPoint = false; this.verticalLines.clear(); this.horizontalLines.clear(); // Find the shapes associated with the current graphic to draw reference lines for it. const objects = this.getObjectsByTarget(target); const points = []; // Collect all the points to draw reference lines. for (const object of objects) points.push(...this.getCaCheMapValue(object)); // Obtain horizontal and vertical reference lines. const { vLines, hLines } = collectLine.call(this, target, points); vLines.forEach(o => { // Objects cannot be deduplicated; convert them to strings for deduplication. this.verticalLines.add(JSON.stringify(o)); }); hLines.forEach(o => { // Objects cannot be deduplicated; convert them to strings for deduplication. this.horizontalLines.add(JSON.stringify(o)); }); } beforeRender() { this.canvas.clearContext(this.canvas.contextTop); } afterRender() { if (this.onlyDrawPoint) { drawPointList.call(this); } else { drawVerticalLine.call(this); drawHorizontalLine.call(this); } } dispose() { this.canvas.off('mouse:up', this.mouseUp); this.canvas.off('object:resizing', this.scalingOrResizing); this.canvas.off('object:scaling', this.scalingOrResizing); this.canvas.off('object:moving', this.moving); this.canvas.off('before:render', this.beforeRender); this.canvas.off('after:render', this.afterRender); } } export { AligningGuidelines }; //# sourceMappingURL=index.mjs.map