UNPKG

11.7 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 RowResizingTool class lets the user resize each row of a named Table Panel in a selected Part.
14 *
15 * If you want to experiment with this extension, try the <a href="../../extensionsJSM/ColumnResizing.html">Column Resizing</a> sample.
16 * @category Tool Extension
17 */
18export class RowResizingTool extends go.Tool {
19 /**
20 * Constructs a RowResizingTool and sets the handle and name of the tool.
21 */
22 constructor() {
23 super();
24 this._tableName = 'TABLE';
25 // internal state
26 this._handle = null;
27 this._adornedTable = null;
28 const h = new go.Shape();
29 h.geometryString = 'M0 0 H14 M0 2 H14';
30 h.desiredSize = new go.Size(14, 2);
31 h.cursor = 'row-resize';
32 h.geometryStretch = go.GraphObject.None;
33 h.background = 'rgba(255,255,255,0.5)';
34 h.stroke = 'rgba(30,144,255,0.5)';
35 this._handleArchetype = h;
36 this.name = 'RowResizing';
37 }
38 /**
39 * Gets or sets small GraphObject that is copied as a resize handle for each row.
40 * This tool expects that this object's {@link GraphObject#desiredSize} (a.k.a width and height) has been set to real numbers.
41 *
42 * The default value is a {@link Shape} that is a narrow rectangle.
43 */
44 get handleArchetype() { return this._handleArchetype; }
45 set handleArchetype(val) { this._handleArchetype = val; }
46 /**
47 * Gets or sets the name of the Table Panel to be resized.
48 *
49 * The default value is the name "TABLE".
50 */
51 get tableName() { return this._tableName; }
52 set tableName(val) { this._tableName = val; }
53 /**
54 * This read-only property returns the {@link GraphObject} that is the tool handle being dragged by the user.
55 * This will be contained by an {@link Adornment} whose category is "RowResizing".
56 * Its {@link Adornment#adornedObject} is the same as the {@link #adornedTable}.
57 */
58 get handle() { return this._handle; }
59 /**
60 * This read-only property returns the {@link Panel} of type {@link Panel.Table} whose rows are being resized.
61 * This must be contained within the selected {@link Part}.
62 */
63 get adornedTable() { return this._adornedTable; }
64 /**
65 * Show an {@link Adornment} with a resize handle at each row.
66 * Don't show anything if {@link #tableName} doesn't identify a {@link Panel}
67 * that has a {@link Panel#type} of type {@link Panel.Table}.
68 */
69 updateAdornments(part) {
70 if (part === null || part instanceof go.Link)
71 return; // this tool never applies to Links
72 if (part.isSelected && !this.diagram.isReadOnly) {
73 const selelt = part.findObject(this.tableName);
74 if (selelt instanceof go.Panel && selelt.actualBounds.isReal() && selelt.isVisibleObject() &&
75 part.actualBounds.isReal() && part.isVisible() &&
76 selelt.type === go.Panel.Table) {
77 const table = selelt;
78 let adornment = part.findAdornment(this.name);
79 if (adornment === null) {
80 adornment = this.makeAdornment(table);
81 part.addAdornment(this.name, adornment);
82 }
83 if (adornment !== null) {
84 const pad = table.padding;
85 const numrows = table.rowCount;
86 // update the position/alignment of each handle
87 adornment.elements.each((h) => {
88 if (!h.pickable)
89 return;
90 const rowdef = table.getRowDefinition(h.row);
91 let hgt = rowdef.actual;
92 if (hgt > 0)
93 hgt = rowdef.total;
94 let sep = 0;
95 // find next non-zero-height row's separatorStrokeWidth
96 let idx = h.row + 1;
97 while (idx < numrows && table.getRowDefinition(idx).actual === 0)
98 idx++;
99 if (idx < numrows) {
100 sep = table.getRowDefinition(idx).separatorStrokeWidth;
101 if (isNaN(sep))
102 sep = table.defaultRowSeparatorStrokeWidth;
103 }
104 h.alignment = new go.Spot(0, 0, pad.left + h.width / 2, pad.top + rowdef.position + hgt + sep / 2);
105 });
106 adornment.locationObject.desiredSize = table.actualBounds.size;
107 adornment.location = table.getDocumentPoint(adornment.locationSpot);
108 adornment.angle = table.getDocumentAngle();
109 return;
110 }
111 }
112 }
113 part.removeAdornment(this.name);
114 }
115 /**
116 * @hidden @internal
117 * @param {Panel} table the Table Panel whose rows may be resized
118 * @return {Adornment}
119 */
120 makeAdornment(table) {
121 // the Adornment is a Spot Panel holding resize handles
122 const adornment = new go.Adornment();
123 adornment.category = this.name;
124 adornment.adornedObject = table;
125 adornment.type = go.Panel.Spot;
126 adornment.locationObjectName = 'BLOCK';
127 // create the "main" element of the Spot Panel
128 const block = new go.TextBlock(); // doesn't matter much what this is
129 block.name = 'BLOCK';
130 block.pickable = false; // it's transparent and not pickable
131 adornment.add(block);
132 // now add resize handles for each row
133 for (let i = 0; i < table.rowCount; i++) {
134 const rowdef = table.getRowDefinition(i);
135 const h = this.makeHandle(table, rowdef);
136 if (h !== null)
137 adornment.add(h);
138 }
139 return adornment;
140 }
141 /**
142 * @hidden @internal
143 * @param {Panel} table the Table Panel whose rows may be resized
144 * @param {RowColumnDefinition} coldef the row definition to be resized
145 * @return a copy of the {@link #handleArchetype}
146 */
147 makeHandle(table, rowdef) {
148 const h = this.handleArchetype;
149 if (h === null)
150 return null;
151 const c = h.copy();
152 c.row = rowdef.index;
153 return c;
154 }
155 /**
156 * This tool may run when there is a mouse-down event on a "RowResizing" handle,
157 * the diagram is not read-only, the left mouse button is being used,
158 * and this tool's adornment's resize handle is at the current mouse point.
159 */
160 canStart() {
161 if (!this.isEnabled)
162 return false;
163 const diagram = this.diagram;
164 if (diagram.isReadOnly)
165 return false;
166 if (!diagram.lastInput.left)
167 return false;
168 const h = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
169 return (h !== null);
170 }
171 /**
172 * Find the {@link #handle}, ensure type {@link Panel.Table}, capture the mouse, and start a transaction.
173 *
174 * If the call to {@link Tool#findToolHandleAt} finds no "RowResizing" tool handle, this method returns without activating this tool.
175 */
176 doActivate() {
177 const diagram = this.diagram;
178 this._handle = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
179 if (this.handle === null)
180 return;
181 const panel = this.handle.part.adornedObject;
182 if (!panel || panel.type !== go.Panel.Table)
183 return;
184 this._adornedTable = panel;
185 diagram.isMouseCaptured = true;
186 this.startTransaction(this.name);
187 this.isActive = true;
188 }
189 /**
190 * Stop the current transaction and release the mouse.
191 */
192 doDeactivate() {
193 this.stopTransaction();
194 this._handle = null;
195 this._adornedTable = null;
196 const diagram = this.diagram;
197 diagram.isMouseCaptured = false;
198 this.isActive = false;
199 }
200 /**
201 * Call {@link #resize} with a new size determined by the current mouse point.
202 * This determines the new bounds by calling {@link #computeResize}.
203 */
204 doMouseMove() {
205 const diagram = this.diagram;
206 if (this.isActive) {
207 const newpt = this.computeResize(diagram.lastInput.documentPoint);
208 this.resize(newpt);
209 }
210 }
211 /**
212 * Call {@link #resize} with the final bounds based on the most recent mouse point, and commit the transaction.
213 * This determines the new bounds by calling {@link #computeResize}.
214 */
215 doMouseUp() {
216 const diagram = this.diagram;
217 if (this.isActive) {
218 const newpt = this.computeResize(diagram.lastInput.documentPoint);
219 this.resize(newpt);
220 this.transactionResult = this.name; // success
221 }
222 this.stopTool();
223 }
224 /**
225 * Change the {@link RowColumnDefinition#height} of the row being resized
226 * to a value corresponding to the given mouse point.
227 * @param {Point} newPoint the value returned by the call to {@link #computeResize}
228 */
229 resize(newPoint) {
230 const table = this.adornedTable;
231 if (table === null)
232 return;
233 const h = this.handle;
234 if (h === null)
235 return;
236 const pad = table.padding;
237 const numrows = table.rowCount;
238 const locpt = table.getLocalPoint(newPoint);
239 const rowdef = table.getRowDefinition(h.row);
240 let sep = 0;
241 let idx = h.row + 1;
242 while (idx < numrows && table.getRowDefinition(idx).actual === 0)
243 idx++;
244 if (idx < numrows) {
245 sep = table.getRowDefinition(idx).separatorStrokeWidth;
246 if (isNaN(sep))
247 sep = table.defaultRowSeparatorStrokeWidth;
248 }
249 rowdef.height = Math.max(0, locpt.y - pad.top - rowdef.position - (rowdef.total - rowdef.actual) - sep / 2);
250 }
251 /**
252 * This can be overridden in order to customize the resizing process.
253 * @expose
254 * @param {Point} p the point where the handle is being dragged.
255 * @return {Point}
256 */
257 computeResize(p) {
258 return p;
259 }
260 /**
261 * Pressing the Delete key removes any column width setting and stops this tool.
262 */
263 doKeyDown() {
264 if (!this.isActive)
265 return;
266 const diagram = this.diagram;
267 const e = diagram.lastInput;
268 if (e.key === 'Del' || e.key === '\t') { // remove height setting
269 if (this.adornedTable !== null && this.handle !== null) {
270 const rowdef = this.adornedTable.getRowDefinition(this.handle.row);
271 rowdef.height = NaN;
272 this.transactionResult = this.name; // success
273 this.stopTool();
274 }
275 }
276 else {
277 super.doKeyDown();
278 }
279 }
280}