|
| 1 | +import type { |
| 2 | + BasicTransformEvent, |
| 3 | + Canvas, |
| 4 | + FabricObject, |
| 5 | + TPointerEventInfo, |
| 6 | +} from 'fabric'; |
| 7 | +import { getFabricWindow } from 'fabric'; |
| 8 | +import type { |
| 9 | + AltMap, |
| 10 | + DistanceGuideProps, |
| 11 | + DrawLineMapProps, |
| 12 | + MovingMap, |
| 13 | +} from './typedefs'; |
| 14 | +import type { DrawTextProps } from './util'; |
| 15 | +import { |
| 16 | + drawAltMap, |
| 17 | + drawLineMap, |
| 18 | + drawMovingMap, |
| 19 | + drawText, |
| 20 | + moving, |
| 21 | + setAltMap, |
| 22 | +} from './util'; |
| 23 | + |
| 24 | +export type { DistanceGuideProps }; |
| 25 | +export class DistanceGuide { |
| 26 | + canvas: Canvas; |
| 27 | + /** The color of the guide line */ |
| 28 | + color = 'rgba(255,0,0,0.9)'; |
| 29 | + /** The fill color of the text */ |
| 30 | + fillStyle = 'rgba(255,255,255,1)'; |
| 31 | + /** The width of the guide line */ |
| 32 | + lineWidth = 1; |
| 33 | + /** The style of the dashed line */ |
| 34 | + lineDash = [6, 2]; |
| 35 | + /** The offset of the dashed line */ |
| 36 | + lineDashOffset = 3; |
| 37 | + /** The size of the text */ |
| 38 | + fontSize = 11; |
| 39 | + /** The fontFamily of the text */ |
| 40 | + fontFamily = 'sans-serif'; |
| 41 | + /** The spacing of the text within the rectangle */ |
| 42 | + padding = 4; |
| 43 | + /** The distance between the text and the guide line */ |
| 44 | + space = 5; |
| 45 | + /** The detection distance when moving the graphic */ |
| 46 | + margin = 8; |
| 47 | + |
| 48 | + altMap?: AltMap; |
| 49 | + movingMap?: MovingMap; |
| 50 | + |
| 51 | + private target?: FabricObject; |
| 52 | + |
| 53 | + constructor(canvas: Canvas, options: Partial<DistanceGuideProps> = {}) { |
| 54 | + this.canvas = canvas; |
| 55 | + Object.assign(this, options); |
| 56 | + this.mouseOver = this.mouseOver.bind(this); |
| 57 | + this.mouseOut = this.mouseOut.bind(this); |
| 58 | + this.mouseDown = this.mouseDown.bind(this); |
| 59 | + this.moving = this.moving.bind(this); |
| 60 | + this.beforeRender = this.beforeRender.bind(this); |
| 61 | + this.afterRender = this.afterRender.bind(this); |
| 62 | + this.keydown = this.keydown.bind(this); |
| 63 | + this.keyup = this.keyup.bind(this); |
| 64 | + this.initBehavior(); |
| 65 | + } |
| 66 | + initBehavior() { |
| 67 | + this.canvas.on('mouse:over', this.mouseOver); |
| 68 | + this.canvas.on('mouse:out', this.mouseOut); |
| 69 | + this.canvas.on('mouse:down', this.mouseDown); |
| 70 | + this.canvas.on('object:moving', this.moving); |
| 71 | + this.canvas.on('before:render', this.beforeRender); |
| 72 | + this.canvas.on('after:render', this.afterRender); |
| 73 | + const win = getFabricWindow(); |
| 74 | + win.addEventListener('keydown', this.keydown); |
| 75 | + win.addEventListener('keyup', this.keyup); |
| 76 | + } |
| 77 | + mouseDown() { |
| 78 | + delete this.altMap; |
| 79 | + this.canvas.once('mouse:up', () => { |
| 80 | + delete this.movingMap; |
| 81 | + }); |
| 82 | + } |
| 83 | + moving(e: BasicTransformEvent & { target: FabricObject }) { |
| 84 | + moving.call(this, e); |
| 85 | + } |
| 86 | + beforeRender() { |
| 87 | + this.canvas.clearContext(this.canvas.contextTop); |
| 88 | + } |
| 89 | + afterRender() { |
| 90 | + drawAltMap.call(this); |
| 91 | + drawMovingMap.call(this); |
| 92 | + } |
| 93 | + mouseOver(e: TPointerEventInfo) { |
| 94 | + const target = e.target; |
| 95 | + this.target = target?.selectable ? target : undefined; |
| 96 | + if (!e.e.altKey) return; |
| 97 | + this.setAltMap(); |
| 98 | + this.canvas.requestRenderAll(); |
| 99 | + } |
| 100 | + mouseOut(e: TPointerEventInfo) { |
| 101 | + this.target = undefined; |
| 102 | + if (!e.e.altKey) return; |
| 103 | + delete this.altMap; |
| 104 | + this.canvas.requestRenderAll(); |
| 105 | + } |
| 106 | + keydown(e: KeyboardEvent) { |
| 107 | + if (e.key != 'Alt') return; |
| 108 | + this.setAltMap(); |
| 109 | + this.canvas.requestRenderAll(); |
| 110 | + } |
| 111 | + keyup(e: KeyboardEvent) { |
| 112 | + if (e.key != 'Alt') return; |
| 113 | + delete this.altMap; |
| 114 | + this.canvas.requestRenderAll(); |
| 115 | + } |
| 116 | + setAltMap(origin = this.canvas._activeObject, target = this.target) { |
| 117 | + setAltMap.call(this, origin, target); |
| 118 | + } |
| 119 | + drawLineMap(props: DrawLineMapProps) { |
| 120 | + drawLineMap.call(this, props); |
| 121 | + } |
| 122 | + drawText(props: DrawTextProps) { |
| 123 | + drawText.call(this, props); |
| 124 | + } |
| 125 | + dispose() { |
| 126 | + this.canvas.off('mouse:over', this.mouseOver); |
| 127 | + this.canvas.off('mouse:out', this.mouseOut); |
| 128 | + this.canvas.off('mouse:down', this.mouseDown); |
| 129 | + this.canvas.off('object:moving', this.moving); |
| 130 | + this.canvas.off('before:render', this.beforeRender); |
| 131 | + this.canvas.off('after:render', this.afterRender); |
| 132 | + const win = getFabricWindow(); |
| 133 | + win.removeEventListener('keydown', this.keydown); |
| 134 | + win.removeEventListener('keyup', this.keyup); |
| 135 | + } |
| 136 | +} |
0 commit comments