UNPKG

7.03 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 OrthogonalLinkReshapingTool class lets a user drag a tool handle along the link segment, which will move the whole segment.
14 *
15 * If you want to experiment with this extension, try the <a href="../../extensionsJSM/OrthogonalLinkReshaping.html">Orthogonal Link Reshaping</a> sample.
16 * @category Tool Extension
17 */
18export class OrthogonalLinkReshapingTool extends go.LinkReshapingTool {
19 /**
20 * Constructs an OrthogonalLinkReshapingTool and sets the name for the tool.
21 */
22 constructor() {
23 super();
24 this._alreadyAddedPoint = false;
25 this.name = 'OrthogonalLinkReshaping';
26 }
27 /**
28 * @hidden @internal
29 * For orthogonal, straight links, create the handles and set reshaping behavior.
30 */
31 makeAdornment(pathshape) {
32 const link = pathshape.part;
33 // add all normal handles first
34 const adornment = super.makeAdornment(pathshape);
35 // add long reshaping handles for orthogonal, straight links
36 if (link !== null && link.isOrthogonal && link.curve !== go.Link.Bezier) {
37 const firstindex = link.firstPickIndex + (link.resegmentable ? 0 : 1);
38 const lastindex = link.lastPickIndex - (link.resegmentable ? 0 : 1);
39 for (let i = firstindex; i < lastindex; i++) {
40 this.makeSegmentDragHandle(link, adornment, i);
41 }
42 }
43 return adornment;
44 }
45 /**
46 * This stops the current reshaping operation and updates any link handles.
47 */
48 doDeactivate() {
49 this._alreadyAddedPoint = false;
50 // when we finish, recreate adornment to ensure proper reshaping behavior/cursor
51 const link = this.adornedLink;
52 if (link !== null && link.isOrthogonal && link.curve !== go.Link.Bezier) {
53 const pathshape = link.path;
54 if (pathshape !== null) {
55 const adornment = this.makeAdornment(pathshape);
56 if (adornment !== null) {
57 link.addAdornment(this.name, adornment);
58 adornment.location = link.position;
59 }
60 }
61 }
62 super.doDeactivate();
63 }
64 /**
65 * Change the route of the {@link #adornedLink} by moving the segment corresponding to the current
66 * {@link #handle} to be at the given {@link Point}.
67 */
68 reshape(newpt) {
69 const link = this.adornedLink;
70 // identify if the handle being dragged is a segment dragging handle
71 if (link !== null && link.isOrthogonal && link.curve !== go.Link.Bezier && this.handle !== null && this.handle.toMaxLinks === 999) {
72 link.startRoute();
73 let index = this.handle.segmentIndex; // for these handles, firstPickIndex <= index < lastPickIndex
74 if (!this._alreadyAddedPoint && link.resegmentable) { // only change the number of points if Link.resegmentable
75 this._alreadyAddedPoint = true;
76 if (index === link.firstPickIndex) {
77 link.insertPoint(index, link.getPoint(index).copy());
78 index++;
79 this.handle.segmentIndex = index;
80 }
81 else if (index === link.lastPickIndex - 1) {
82 link.insertPoint(index, link.getPoint(index).copy());
83 if (index - 1 === link.firstPickIndex + 1)
84 this.handle.segmentIndex = index - 1;
85 }
86 }
87 const behavior = this.getReshapingBehavior(this.handle);
88 if (behavior === go.LinkReshapingTool.Vertical) {
89 // move segment vertically
90 link.setPointAt(index, link.getPoint(index - 1).x, newpt.y);
91 link.setPointAt(index + 1, link.getPoint(index + 2).x, newpt.y);
92 }
93 else if (behavior === go.LinkReshapingTool.Horizontal) {
94 // move segment horizontally
95 link.setPointAt(index, newpt.x, link.getPoint(index - 1).y);
96 link.setPointAt(index + 1, newpt.x, link.getPoint(index + 2).y);
97 }
98 link.commitRoute();
99 }
100 else {
101 super.reshape(newpt);
102 }
103 }
104 /**
105 * Create the segment dragging handles.
106 * There are two parts: one invisible handle that spans the segment, and a visible handle at the middle of the segment.
107 * These are inserted at the front of the adornment such that the normal handles have priority.
108 */
109 makeSegmentDragHandle(link, adornment, index) {
110 const a = link.getPoint(index);
111 let b = link.getPoint(index + 1);
112 const seglength = Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y));
113 // determine segment orientation
114 let orient = '';
115 if (this.isApprox(a.x, b.x) && this.isApprox(a.y, b.y)) {
116 b = link.getPoint(index - 1);
117 if (this.isApprox(a.x, b.x)) {
118 orient = 'vertical';
119 }
120 else if (this.isApprox(a.y, b.y)) {
121 orient = 'horizontal';
122 }
123 }
124 else {
125 if (this.isApprox(a.x, b.x)) {
126 orient = 'vertical';
127 }
128 else if (this.isApprox(a.y, b.y)) {
129 orient = 'horizontal';
130 }
131 }
132 // make an invisible handle along the whole segment
133 const h = new go.Shape();
134 h.strokeWidth = 6;
135 h.opacity = 0;
136 h.segmentOrientation = go.Link.OrientAlong;
137 h.segmentIndex = index;
138 h.segmentFraction = 0.5;
139 h.toMaxLinks = 999; // set this unsused property to easily identify that we have a segment dragging handle
140 if (orient === 'horizontal') {
141 this.setReshapingBehavior(h, go.LinkReshapingTool.Vertical);
142 h.cursor = 'n-resize';
143 }
144 else {
145 this.setReshapingBehavior(h, go.LinkReshapingTool.Horizontal);
146 h.cursor = 'w-resize';
147 }
148 h.geometryString = 'M 0 0 L ' + seglength + ' 0';
149 adornment.insertAt(0, h);
150 }
151 /**
152 * Compare two numbers to ensure they are almost equal.
153 * Used in this class for comparing coordinates of Points.
154 */
155 isApprox(x, y) {
156 const d = x - y;
157 return d < 0.5 && d > -0.5;
158 }
159}