UNPKG

6.83 kBJavaScriptView Raw
1/*
2* Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved.
3*/
4/*
5* This is an extension and not part of the main GoJS library.
6* Note that the API for this class may change with any version, even point releases.
7* If you intend to use an extension in production, you should copy the code to your own source directory.
8* Extensions can be found in the GoJS kit under the extensions or extensionsTS folders.
9* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
10*/
11import * as go from '../release/go-module.js';
12/**
13 * The LinkLabelDraggingTool class lets the user move a label on a {@link Link}.
14 *
15 * This tool only works when the Link has a label
16 * that is positioned at the {@link Link#midPoint} plus some offset.
17 * It does not work for labels that have a particular {@link GraphObject#segmentIndex}.
18 *
19 * If you want to experiment with this extension, try the <a href="../../extensionsJSM/LinkLabelDragging.html">Link Label Dragging</a> sample.
20 * @category Tool Extension
21 */
22export class LinkLabelDraggingTool extends go.Tool {
23 /**
24 * Constructs a LinkLabelDraggingTool and sets the name for the tool.
25 */
26 constructor() {
27 super();
28 /**
29 * The label being dragged.
30 */
31 this.label = null;
32 this._offset = new go.Point(); // of the mouse relative to the center of the label object
33 this._originalOffset = null;
34 this.name = 'LinkLabelDragging';
35 }
36 /**
37 * From the GraphObject at the mouse point, search up the visual tree until we get to
38 * an object that is a label of a Link.
39 * @return {GraphObject} This returns null if no such label is at the mouse down point.
40 */
41 findLabel() {
42 const diagram = this.diagram;
43 const e = diagram.lastInput;
44 let elt = diagram.findObjectAt(e.documentPoint, null, null);
45 if (elt === null || !(elt.part instanceof go.Link))
46 return null;
47 while (elt !== null && elt.panel !== elt.part) {
48 elt = elt.panel;
49 }
50 // If it's at an arrowhead segment index, don't consider it a label:
51 if (elt !== null && (elt.segmentIndex === 0 || elt.segmentIndex === -1))
52 return null;
53 return elt;
54 }
55 /**
56 * This tool can only start if the mouse has moved enough so that it is not a click,
57 * and if the mouse down point is on a GraphObject "label" in a Link Panel,
58 * as determined by {@link #findLabel}.
59 */
60 canStart() {
61 if (!super.canStart())
62 return false;
63 const diagram = this.diagram;
64 // require left button & that it has moved far enough away from the mouse down point, so it isn't a click
65 const e = diagram.lastInput;
66 if (!e.left)
67 return false;
68 if (!this.isBeyondDragSize())
69 return false;
70 return this.findLabel() !== null;
71 }
72 /**
73 * Start a transaction, call {@link #findLabel} and remember it as the "label" property,
74 * and remember the original value for the label's {@link GraphObject#segmentOffset} property.
75 */
76 doActivate() {
77 this.startTransaction('Shifted Label');
78 this.label = this.findLabel();
79 if (this.label !== null) {
80 // compute the offset of the mouse-down point relative to the center of the label
81 this._offset = this.diagram.firstInput.documentPoint.copy().subtract(this.label.getDocumentPoint(go.Spot.Center));
82 this._originalOffset = this.label.segmentOffset.copy();
83 }
84 super.doActivate();
85 }
86 /**
87 * Stop any ongoing transaction.
88 */
89 doDeactivate() {
90 super.doDeactivate();
91 this.stopTransaction();
92 }
93 /**
94 * Clear any reference to a label element.
95 */
96 doStop() {
97 this.label = null;
98 super.doStop();
99 }
100 /**
101 * Restore the label's original value for {@link GraphObject#segmentOffset}.
102 */
103 doCancel() {
104 if (this.label !== null && this._originalOffset !== null) {
105 this.label.segmentOffset = this._originalOffset;
106 }
107 super.doCancel();
108 }
109 /**
110 * During the drag, call {@link #updateSegmentOffset} in order to set
111 * the {@link GraphObject#segmentOffset} of the label.
112 */
113 doMouseMove() {
114 if (!this.isActive)
115 return;
116 this.updateSegmentOffset();
117 }
118 /**
119 * At the end of the drag, update the segment offset of the label and finish the tool,
120 * completing a transaction.
121 */
122 doMouseUp() {
123 if (!this.isActive)
124 return;
125 this.updateSegmentOffset();
126 this.transactionResult = 'Shifted Label';
127 this.stopTool();
128 }
129 /**
130 * Save the label's {@link GraphObject#segmentOffset} as a rotated offset from the midpoint of the
131 * Link that the label is in.
132 */
133 updateSegmentOffset() {
134 const lab = this.label;
135 if (lab === null)
136 return;
137 const link = lab.part;
138 if (!(link instanceof go.Link))
139 return;
140 const last = this.diagram.lastInput.documentPoint;
141 const idx = lab.segmentIndex;
142 const numpts = link.pointsCount;
143 // if the label is a "mid" label, assume it is positioned differently from a label at a particular segment
144 if (idx < -numpts || idx >= numpts) {
145 const mid = link.midPoint;
146 // need to rotate this point to account for the angle of the link segment at the mid-point
147 const p = new go.Point(last.x - this._offset.x - mid.x, last.y - this._offset.y - mid.y);
148 lab.segmentOffset = p.rotate(-link.midAngle);
149 }
150 else { // handle the label point being on a partiular segment with a given fraction
151 const frac = lab.segmentFraction;
152 let a;
153 let b;
154 if (idx >= 0) { // indexing forwards
155 a = link.getPoint(idx);
156 b = (idx < numpts - 1) ? link.getPoint(idx + 1) : a;
157 }
158 else { // or backwards if segmentIndex is negative
159 const i = numpts + idx;
160 a = link.getPoint(i);
161 b = (i > 0) ? link.getPoint(i - 1) : a;
162 }
163 const labx = a.x + (b.x - a.x) * frac;
164 const laby = a.y + (b.y - a.y) * frac;
165 const p = new go.Point(last.x - this._offset.x - labx, last.y - this._offset.y - laby);
166 const segangle = (idx >= 0) ? a.directionPoint(b) : b.directionPoint(a);
167 lab.segmentOffset = p.rotate(-segangle);
168 }
169 }
170}