1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import * as go from '../release/go-module.js';
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export class SectorReshapingTool extends go.Tool {
|
26 | private _handle: go.GraphObject | null = null;
|
27 | private _originalRadius: number = 0;
|
28 | private _originalAngle: number = 0;
|
29 | private _originalSweep: number = 0;
|
30 |
|
31 | private _radiusProperty: string = 'radius';
|
32 | private _angleProperty: string = 'angle';
|
33 | private _sweepProperty: string = 'sweep';
|
34 |
|
35 | |
36 |
|
37 |
|
38 | constructor() {
|
39 | super();
|
40 | this.name = 'SectorReshaping';
|
41 | }
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 | get radiusProperty(): string { return this._radiusProperty; }
|
49 | set radiusProperty(val: string) { this._radiusProperty = val; }
|
50 |
|
51 | |
52 |
|
53 |
|
54 |
|
55 |
|
56 | get angleProperty(): string { return this._angleProperty; }
|
57 | set angleProperty(val: string) { this._angleProperty = val; }
|
58 |
|
59 | |
60 |
|
61 |
|
62 |
|
63 |
|
64 | get sweepProperty(): string { return this._sweepProperty; }
|
65 | set sweepProperty(val: string) { this._sweepProperty = val; }
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 | public canStart(): boolean {
|
72 | if (!this.isEnabled) return false;
|
73 | const diagram = this.diagram;
|
74 | if (diagram.isReadOnly) return false;
|
75 | if (!diagram.allowReshape) return false;
|
76 | const h = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
|
77 | return (h !== null);
|
78 | }
|
79 |
|
80 | |
81 |
|
82 |
|
83 | public updateAdornments(part: go.Part): void {
|
84 | const data = part.data;
|
85 | if (part.isSelected && data !== null && !this.diagram.isReadOnly) {
|
86 | let ad = part.findAdornment(this.name);
|
87 | if (ad === null) {
|
88 | const $ = go.GraphObject.make;
|
89 | ad =
|
90 | $(go.Adornment, 'Spot',
|
91 | $(go.Placeholder),
|
92 | $(go.Shape, 'Diamond',
|
93 | { name: 'RADIUS', fill: 'lime', width: 10, height: 10, cursor: 'move' },
|
94 | new go.Binding('alignment', '', (d) => {
|
95 | const angle = SectorReshapingTool.getAngle(d);
|
96 | const sweep = SectorReshapingTool.getSweep(d);
|
97 | const p = new go.Point(0.5, 0).rotate(angle + sweep / 2);
|
98 | return new go.Spot(0.5 + p.x, 0.5 + p.y);
|
99 | })),
|
100 | $(go.Shape, 'Circle',
|
101 | { name: 'ANGLE', fill: 'lime', width: 8, height: 8, cursor: 'move' },
|
102 | new go.Binding('alignment', '', (d) => {
|
103 | const angle = SectorReshapingTool.getAngle(d);
|
104 | const p = new go.Point(0.5, 0).rotate(angle);
|
105 | return new go.Spot(0.5 + p.x, 0.5 + p.y);
|
106 | })),
|
107 | $(go.Shape, 'Circle',
|
108 | { name: 'SWEEP', fill: 'lime', width: 8, height: 8, cursor: 'move' },
|
109 | new go.Binding('alignment', '', (d) => {
|
110 | const angle = SectorReshapingTool.getAngle(d);
|
111 | const sweep = SectorReshapingTool.getSweep(d);
|
112 | const p = new go.Point(0.5, 0).rotate(angle + sweep);
|
113 | return new go.Spot(0.5 + p.x, 0.5 + p.y);
|
114 | }))
|
115 | ) as go.Adornment;
|
116 | ad.adornedObject = part.locationObject;
|
117 | part.addAdornment(this.name, ad);
|
118 | } else {
|
119 | ad.location = part.position;
|
120 | const ns = part.naturalBounds;
|
121 | if (ad.placeholder !== null) ad.placeholder.desiredSize = new go.Size((ns.width) * part.scale, (ns.height) * part.scale);
|
122 | ad.updateTargetBindings();
|
123 | }
|
124 | } else {
|
125 | part.removeAdornment(this.name);
|
126 | }
|
127 | }
|
128 |
|
129 | |
130 |
|
131 |
|
132 | public doActivate(): void {
|
133 | const diagram = this.diagram;
|
134 | this._handle = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
|
135 | if (this._handle === null) return;
|
136 | const part = (this._handle.part as go.Adornment).adornedPart;
|
137 | if (part === null || part.data === null) return;
|
138 |
|
139 | const data = part.data;
|
140 | this._originalRadius = SectorReshapingTool.getRadius(data);
|
141 | this._originalAngle = SectorReshapingTool.getAngle(data);
|
142 | this._originalSweep = SectorReshapingTool.getSweep(data);
|
143 |
|
144 | this.startTransaction(this.name);
|
145 | this.isActive = true;
|
146 | }
|
147 |
|
148 | |
149 |
|
150 |
|
151 | public doDeactivate(): void {
|
152 | this.stopTransaction();
|
153 |
|
154 | this._handle = null;
|
155 | this.isActive = false;
|
156 | }
|
157 |
|
158 | |
159 |
|
160 |
|
161 | public doCancel(): void {
|
162 | if (this._handle !== null) {
|
163 | const part = (this._handle.part as go.Adornment).adornedPart;
|
164 | if (part !== null) {
|
165 | const model = this.diagram.model;
|
166 | model.setDataProperty(part.data, this._radiusProperty, this._originalRadius);
|
167 | model.setDataProperty(part.data, this._angleProperty, this._originalAngle);
|
168 | model.setDataProperty(part.data, this._sweepProperty, this._originalSweep);
|
169 | }
|
170 | }
|
171 | this.stopTool();
|
172 | }
|
173 |
|
174 | |
175 |
|
176 |
|
177 |
|
178 |
|
179 | public doMouseMove(): void {
|
180 | const diagram = this.diagram;
|
181 | const h = this._handle;
|
182 | if (this.isActive && h !== null) {
|
183 | const adorned = (h.part as go.Adornment).adornedObject;
|
184 | if (adorned === null) return;
|
185 | const center = adorned.getDocumentPoint(go.Spot.Center);
|
186 | const node = adorned.part;
|
187 | if (node === null || node.data === null) return;
|
188 | const mouse = diagram.lastInput.documentPoint;
|
189 | if (h.name === 'RADIUS') {
|
190 | const dst = Math.sqrt(center.distanceSquaredPoint(mouse));
|
191 | diagram.model.setDataProperty(node.data, this._radiusProperty, dst);
|
192 | } else if (h.name === 'ANGLE') {
|
193 | const dir = center.directionPoint(mouse);
|
194 | diagram.model.setDataProperty(node.data, this._angleProperty, dir);
|
195 | } else if (h.name === 'SWEEP') {
|
196 | const dir = center.directionPoint(mouse);
|
197 | const ang = SectorReshapingTool.getAngle(node.data);
|
198 | let swp = (dir - ang + 360) % 360;
|
199 | if (swp > 359) swp = 360;
|
200 | diagram.model.setDataProperty(node.data, this._sweepProperty, swp);
|
201 | }
|
202 | }
|
203 | }
|
204 |
|
205 | |
206 |
|
207 |
|
208 | public doMouseUp(): void {
|
209 | const diagram = this.diagram;
|
210 | if (this.isActive) {
|
211 | this.transactionResult = this.name;
|
212 | }
|
213 | this.stopTool();
|
214 | }
|
215 |
|
216 |
|
217 |
|
218 | public static getRadius(data: go.ObjectData): number {
|
219 | let radius = data['radius'];
|
220 | if (!(typeof radius === 'number') || isNaN(radius) || radius <= 0) radius = 50;
|
221 | return radius;
|
222 | }
|
223 |
|
224 |
|
225 | public static getAngle(data: go.ObjectData): number {
|
226 | let angle = data['angle'];
|
227 | if (!(typeof angle === 'number') || isNaN(angle)) angle = 0;
|
228 | else angle = angle % 360;
|
229 | return angle;
|
230 | }
|
231 |
|
232 |
|
233 | public static getSweep(data: go.ObjectData): number {
|
234 | let sweep = data['sweep'];
|
235 | if (!(typeof sweep === 'number') || isNaN(sweep)) sweep = 360;
|
236 | return sweep;
|
237 | }
|
238 | }
|