@hpcc-js/layout 3.5.7 → 3.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Grid.ts CHANGED
@@ -1,576 +1,576 @@
1
- import { d3Event, drag as d3Drag, HTMLWidget, Platform, select as d3Select, Utility } from "@hpcc-js/common";
2
- import * as _GridList from "grid-list";
3
- import { Cell } from "./Cell.ts";
4
-
5
- import "../src/Grid.css";
6
-
7
- const GridList = (_GridList && _GridList.default) || _GridList;
8
-
9
- export type ICellPosition = [number, number, number, number];
10
-
11
- export class Grid extends HTMLWidget {
12
- divItems;
13
-
14
- gridList;
15
- items;
16
- itemsMap;
17
- origItems;
18
- cellWidth;
19
- cellHeight;
20
- dragItem;
21
- dragItemPos;
22
-
23
- _d3Drag;
24
- _d3DragResize;
25
- _selectionBag;
26
- _scrollBarWidth;
27
-
28
- constructor() {
29
- super();
30
-
31
- this._tag = "div";
32
- this._selectionBag = new Utility.Selection(this);
33
-
34
- this.content([]);
35
- }
36
-
37
- getDimensions() {
38
- const size = { width: 0, height: 0 };
39
- this.content().forEach(function (cell) {
40
- if (size.width < cell.gridCol() + cell.gridColSpan()) {
41
- size.width = cell.gridCol() + cell.gridColSpan();
42
- }
43
- if (size.height < cell.gridRow() + cell.gridRowSpan()) {
44
- size.height = cell.gridRow() + cell.gridRowSpan();
45
- }
46
- }, this);
47
- return size;
48
- }
49
-
50
- clearContent(widget) {
51
- this.content(this.content().filter(function (contentWidget) {
52
- if (!widget) {
53
- contentWidget.target(null);
54
- return false;
55
- }
56
- let w: any = contentWidget;
57
- while (w) {
58
- if (widget === w) {
59
- contentWidget.target(null);
60
- return false;
61
- }
62
- w = w.widget ? w.widget() : null;
63
- }
64
- return true;
65
- }));
66
- }
67
-
68
- setContent(row, col, widget, title?, rowSpan?, colSpan?) {
69
- rowSpan = rowSpan || 1;
70
- colSpan = colSpan || 1;
71
- title = title || "";
72
- this.content(this.content().filter(function (contentWidget) {
73
- if (contentWidget.gridRow() === row && contentWidget.gridCol() === col) {
74
- contentWidget.target(null);
75
- return false;
76
- }
77
- return true;
78
- }));
79
- if (widget) {
80
- const cell = new Cell()
81
- .gridRow(row)
82
- .gridCol(col)
83
- .widget(widget)
84
- .title(title)
85
- .gridRowSpan(rowSpan)
86
- .gridColSpan(colSpan)
87
- ;
88
- this.content().push(cell);
89
- }
90
- return this;
91
- }
92
-
93
- sortedContent() {
94
- return this.content().sort(function (l, r) {
95
- if (l.gridRow() === r.gridRow()) {
96
- return l.gridCol() - r.gridCol();
97
- }
98
- return l.gridRow() - r.gridRow();
99
- });
100
- }
101
-
102
- getCell(row, col) {
103
- let retVal = null;
104
- this.content().some(function (cell) {
105
- if (row >= cell.gridRow() && row < cell.gridRow() + cell.gridRowSpan() &&
106
- col >= cell.gridCol() && col < cell.gridCol() + cell.gridColSpan()) {
107
- retVal = cell;
108
- return true;
109
- }
110
- return false;
111
- });
112
- return retVal;
113
- }
114
-
115
- getWidgetCell(id) {
116
- let retVal = null;
117
- this.content().some(function (cell) {
118
- if (cell.widget().id() === id) {
119
- retVal = cell;
120
- return true;
121
- }
122
- return false;
123
- });
124
- return retVal;
125
- }
126
-
127
- getContent(id) {
128
- let retVal = null;
129
- this.content().some(function (cell) {
130
- if (cell.widget().id() === id) {
131
- retVal = cell.widget();
132
- return true;
133
- }
134
- return false;
135
- });
136
- return retVal;
137
- }
138
-
139
- cellToGridItem(cell) {
140
- return {
141
- x: cell.gridCol(),
142
- y: cell.gridRow(),
143
- w: cell.gridColSpan(),
144
- h: cell.gridRowSpan(),
145
- id: cell.id(),
146
- cell
147
- };
148
- }
149
-
150
- gridItemToCell(item) {
151
- item.cell
152
- .gridCol(item.x)
153
- .gridRow(item.y)
154
- .gridColSpan(item.w)
155
- .gridRowSpan(item.h)
156
- ;
157
- }
158
-
159
- resetItemsPos() {
160
- this.origItems.forEach(function (origItem) {
161
- const item = this.itemsMap[origItem.id];
162
- item.x = origItem.x;
163
- item.y = origItem.y;
164
- }, this);
165
- }
166
-
167
- initGridList() {
168
- this.itemsMap = {};
169
- this.items = this.content().map(function (cell) {
170
- const retVal = this.cellToGridItem(cell);
171
- this.itemsMap[retVal.id] = retVal;
172
- return retVal;
173
- }, this);
174
- this.origItems = this.content().map(this.cellToGridItem);
175
- this.gridList = new GridList(this.items, {
176
- direction: this.snapping(),
177
- lanes: this.snapping() === "horizontal" ? this.snappingRows() : this.snappingColumns()
178
- });
179
- }
180
-
181
- killGridList() {
182
- this.gridList = null;
183
- delete this.items;
184
- delete this.itemsMap;
185
- }
186
-
187
- enter(domNode, element) {
188
- super.enter(domNode, element);
189
-
190
- this._scrollBarWidth = Platform.getScrollbarWidth();
191
-
192
- const context = this;
193
- this._d3Drag = d3Drag()
194
- .subject(function (_d) {
195
- const d = context.cellToGridItem(_d);
196
- return { x: d.x * context.cellWidth, y: d.y * context.cellHeight };
197
- })
198
- .on("start", function (_d: any) {
199
- if (!context.designMode()) return;
200
- d3Event().sourceEvent.stopPropagation();
201
- context.initGridList();
202
- const d = context.itemsMap[_d.id()];
203
- context.dragItem = element.append("div")
204
- .attr("class", "dragging")
205
- .style("transform", function () { return "translate(" + d.x * context.cellWidth + "px, " + d.y * context.cellHeight + "px)"; })
206
- .style("width", function () { return d.w * context.cellWidth - context.gutter() + "px"; })
207
- .style("height", function () { return d.h * context.cellHeight - context.gutter() + "px"; })
208
- ;
209
- context.selectionBagClick(_d);
210
- })
211
- .on("drag", function (_d: any) {
212
- if (!context.designMode()) return;
213
- const event = d3Event();
214
- event.sourceEvent.stopPropagation();
215
- const d = context.itemsMap[_d.id()];
216
- if (event.x < 0) {
217
- event.x = 0;
218
- }
219
- if (event.x + d.w * context.cellWidth > context.snappingColumns() * context.cellWidth) {
220
- event.x = context.snappingColumns() * context.cellWidth - d.w * context.cellWidth;
221
- }
222
- if (event.y < 0) {
223
- event.y = 0;
224
- }
225
- if (event.y + d.h * context.cellWidth > context.snappingRows() * context.cellWidth) {
226
- event.y = context.snappingRows() * context.cellWidth - d.h * context.cellWidth;
227
- }
228
- const pos = [Math.max(0, Math.floor((event.x + context.cellWidth / 2) / context.cellWidth)), Math.max(0, Math.floor((event.y + context.cellHeight / 2) / context.cellHeight))];
229
- if (d.x !== pos[0] || d.y !== pos[1]) {
230
- if (context.snapping() !== "none") {
231
- context.resetItemsPos();
232
- context.gridList.moveItemToPosition(d, pos);
233
- } else {
234
- d.x = pos[0];
235
- d.y = pos[1];
236
- }
237
- if (_d.gridCol() !== d.x || _d.gridRow() !== d.y) {
238
- context.items.forEach(context.gridItemToCell);
239
- context.updateGrid(false, 100);
240
- }
241
- }
242
- context.dragItem
243
- .style("transform", function () { return "translate(" + event.x + "px, " + event.y + "px)"; })
244
- .style("width", function () { return d.w * context.cellWidth + "px"; })
245
- .style("height", function () { return d.h * context.cellHeight + "px"; })
246
- ;
247
- })
248
- .on("end", function () {
249
- if (!context.designMode()) return;
250
- d3Event().sourceEvent.stopPropagation();
251
- context.dragItem.remove();
252
- context.dragItem = null;
253
- context.killGridList();
254
- })
255
- ;
256
-
257
- this._d3DragResize = d3Drag()
258
- .subject(function (_d) {
259
- const d = context.cellToGridItem(_d);
260
- return { x: (d.x + d.w - 1) * context.cellWidth, y: (d.y + d.h - 1) * context.cellHeight };
261
- })
262
- .on("start", function (_d: any) {
263
- if (!context.designMode()) return;
264
- d3Event().sourceEvent.stopPropagation();
265
- context.initGridList();
266
- const d = context.itemsMap[_d.id()];
267
- context.dragItem = element.append("div")
268
- .attr("class", "resizing")
269
- .style("transform", function () { return "translate(" + d.x * context.cellWidth + "px, " + d.y * context.cellHeight + "px)"; })
270
- .style("width", function () { return d.w * context.cellWidth - context.gutter() + "px"; })
271
- .style("height", function () { return d.h * context.cellHeight - context.gutter() + "px"; })
272
- ;
273
- context.dragItemPos = { x: d.x, y: d.y };
274
- })
275
- .on("drag", function (_d: any) {
276
- if (!context.designMode()) return;
277
- const event = d3Event();
278
- event.sourceEvent.stopPropagation();
279
- const d = context.itemsMap[_d.id()];
280
- const pos = [Math.max(0, Math.round(event.x / context.cellWidth)), Math.max(0, Math.round(event.y / context.cellHeight))];
281
- const size = {
282
- w: Math.max(1, pos[0] - d.x + 1),
283
- h: Math.max(1, pos[1] - d.y + 1)
284
- };
285
- if (d.w !== size.w || d.h !== size.h) {
286
- if (context.snapping() !== "none") {
287
- context.resetItemsPos();
288
- context.gridList.resizeItem(d, size);
289
- } else {
290
- d.w = size.w;
291
- d.h = size.h;
292
- }
293
- if (_d.gridColSpan() !== d.w || _d.gridRowSpan() !== d.h) {
294
- context.items.forEach(context.gridItemToCell);
295
- context.updateGrid(d.id, 100);
296
- }
297
- }
298
- context.dragItem
299
- .style("width", function () { return (-d.x + 1) * context.cellWidth + event.x - context.gutter() + "px"; })
300
- .style("height", function () { return (-d.y + 1) * context.cellHeight + event.y - context.gutter() + "px"; })
301
- ;
302
- })
303
- .on("end", function () {
304
- if (!context.designMode()) return;
305
- d3Event().sourceEvent.stopPropagation();
306
- context.dragItem.remove();
307
- context.dragItem = null;
308
- context.killGridList();
309
- })
310
- ;
311
- }
312
-
313
- updateGrid(resize, transitionDuration: number = 0, _noRender: boolean = false) {
314
- transitionDuration = transitionDuration || 0;
315
- const context = this;
316
- this.divItems
317
- .classed("draggable", this.designMode())
318
- .transition().duration(transitionDuration)
319
- .style("left", function (d) { return d.gridCol() * context.cellWidth + context.gutter() / 2 + "px"; })
320
- .style("top", function (d) { return d.gridRow() * context.cellHeight + context.gutter() / 2 + "px"; })
321
- .style("width", function (d) { return d.gridColSpan() * context.cellWidth - context.gutter() + "px"; })
322
- .style("height", function (d) { return d.gridRowSpan() * context.cellHeight - context.gutter() + "px"; })
323
- .on("end", function (d) {
324
- d
325
- .surfaceShadow_default(context.surfaceShadow())
326
- .surfacePadding_default(context.surfacePadding())
327
- .surfaceBorderWidth_default(context.surfaceBorderWidth())
328
- .surfaceBackgroundColor_default(context.surfaceBackgroundColor())
329
- ;
330
-
331
- if (resize === true || resize === d.id()) {
332
- d
333
- .resize()
334
- .lazyRender()
335
- ;
336
- }
337
- })
338
- ;
339
- }
340
-
341
- update(domNode, element2) {
342
- super.update(domNode, element2);
343
-
344
- this._placeholderElement.style("overflow-x", this.fitTo() === "width" ? "hidden" : null);
345
- this._placeholderElement.style("overflow-y", this.fitTo() === "width" ? "scroll" : null);
346
- const dimensions = this.getDimensions();
347
- const clientWidth = this.width() - (this.fitTo() === "width" ? this._scrollBarWidth : 0);
348
- this.cellWidth = clientWidth / dimensions.width;
349
- this.cellHeight = this.fitTo() === "all" ? this.height() / dimensions.height : this.cellWidth;
350
- if (this.designMode()) {
351
- const cellLaneRatio = Math.min(this.width() / this.snappingColumns(), this.height() / this.snappingRows());
352
- const laneWidth = Math.floor(cellLaneRatio);
353
- this.cellWidth = laneWidth;
354
- this.cellHeight = this.cellWidth;
355
- }
356
-
357
- // Grid ---
358
- const context = this;
359
- const divItems = element2.selectAll("#" + this.id() + " > .ddCell").data(this.content(), function (d) { return d.id(); });
360
- this.divItems = divItems.enter().append("div")
361
- .attr("class", "ddCell")
362
- .each(function (d) {
363
- d.target(this);
364
- d.__grid_watch = d.monitor(function (key, newVal, oldVal) {
365
- if (context._renderCount && (key === "snapping" || key.indexOf("grid") === 0) && newVal !== oldVal) {
366
- if (!context.gridList) {
367
- // API Call (only needed when not dragging) ---
368
- context.initGridList();
369
- if (context.snapping() !== "none") {
370
- context.gridList.resizeGrid(context.snapping() === "horizontal" ? context.snappingRows() : context.snappingColumns());
371
- }
372
- context.items.forEach(context.gridItemToCell);
373
- context.updateGrid(d.id(), 100);
374
- context.killGridList();
375
- }
376
- }
377
- });
378
- const element = d3Select(this);
379
- element.append("div")
380
- .attr("class", "resizeHandle")
381
- .call(context._d3DragResize)
382
- .append("div")
383
- .attr("class", "resizeHandleDisplay")
384
- ;
385
- }).merge(divItems)
386
- ;
387
- this.divItems.each(function (d) {
388
- const element = d3Select(this);
389
- if (context.designMode()) {
390
- element.call(context._d3Drag);
391
- } else {
392
- element
393
- .on("mousedown.drag", null)
394
- .on("touchstart.drag", null)
395
- ;
396
- }
397
- });
398
- this.divItems.select(".resizeHandle")
399
- .style("display", this.designMode() ? null : "none")
400
- ;
401
-
402
- this.updateGrid(true);
403
- divItems.exit()
404
- .each(function (d) {
405
- d.target(null);
406
- if (d.__grid_watch) {
407
- d.__grid_watch.remove();
408
- }
409
- })
410
- .remove()
411
- ;
412
-
413
- // Snapping ---
414
- const lanesBackground = element2.selectAll("#" + this.id() + " > .laneBackground").data(this.designMode() ? [""] : []);
415
- lanesBackground.enter().insert("div", ":first-child")
416
- .attr("class", "laneBackground")
417
- .style("left", "1px")
418
- .style("top", "1px")
419
- .on("click", function () {
420
- context.selectionBagClear();
421
- })
422
- .merge(lanesBackground)
423
- .style("width", (this.snappingColumns() * this.cellWidth) + "px")
424
- .style("height", (this.snappingRows() * this.cellHeight) + "px")
425
- ;
426
- lanesBackground.exit()
427
- .each(function () {
428
- context.selectionBagClear();
429
- })
430
- .remove()
431
- ;
432
-
433
- const lanes = element2.selectAll("#" + this.id() + " > .lane").data(this.designMode() ? [""] : []);
434
- lanes.enter().append("div")
435
- .attr("class", "lane")
436
- .style("left", "1px")
437
- .style("top", "1px")
438
- ;
439
- lanes
440
- .style("display", this.showLanes() ? null : "none")
441
- .style("width", (this.snappingColumns() * this.cellWidth) + "px")
442
- .style("height", (this.snappingRows() * this.cellHeight) + "px")
443
- .style("background-image", "linear-gradient(to right, grey 1px, transparent 1px), linear-gradient(to bottom, grey 1px, transparent 1px)")
444
- .style("background-size", this.cellWidth + "px " + this.cellHeight + "px")
445
- ;
446
- lanes.exit()
447
- .remove()
448
- ;
449
- }
450
-
451
- exit(domNode, element) {
452
- this.content().forEach(w => w.target(null));
453
- super.exit(domNode, element);
454
- }
455
-
456
- _createSelectionObject(d) {
457
- return {
458
- _id: d._id,
459
- element: () => {
460
- return d._element;
461
- },
462
- widget: d
463
- };
464
- }
465
-
466
- selection(_) {
467
- if (!arguments.length) return this._selectionBag.get().map(function (d) { return d._id; });
468
- this._selectionBag.set(_.map(function (row) {
469
- return this._createSelectionObject(row);
470
- }, this));
471
- return this;
472
- }
473
-
474
- selectionBagClear() {
475
- if (!this._selectionBag.isEmpty()) {
476
- this._selectionBag.clear();
477
- this.postSelectionChange();
478
- }
479
- }
480
-
481
- selectionBagClick(d) {
482
- if (d !== null) {
483
- const selectionObj = this._createSelectionObject(d);
484
- if (d3Event().sourceEvent.ctrlKey) {
485
- if (this._selectionBag.isSelected(selectionObj)) {
486
- this._selectionBag.remove(selectionObj);
487
- this.postSelectionChange();
488
- } else {
489
- this._selectionBag.append(selectionObj);
490
- this.postSelectionChange();
491
- }
492
- } else {
493
- const selected = this._selectionBag.get();
494
- if (selected.length === 1 && selected[0]._id === selectionObj._id) {
495
- this.selectionBagClear();
496
- } else {
497
- this._selectionBag.set([selectionObj]);
498
- }
499
- this.postSelectionChange();
500
- }
501
- }
502
- }
503
-
504
- postSelectionChange() {
505
- }
506
-
507
- applyLayout(layoutArr: ICellPosition[]) {
508
- this.divItems.each((d, i) => {
509
- if (layoutArr[i]) {
510
- const [x, y, w, h] = layoutArr[i];
511
- d
512
- .gridCol(x)
513
- .gridRow(y)
514
- .gridColSpan(w)
515
- .gridRowSpan(h)
516
- ;
517
- }
518
- });
519
- this.updateGrid(true);
520
- }
521
-
522
- vizActivation(elem) {
523
- }
524
- }
525
- Grid.prototype._class += " layout_Grid";
526
-
527
- export interface Grid {
528
- designMode(): boolean;
529
- designMode(_: boolean): this;
530
- showLanes(): boolean;
531
- showLanes(_: boolean): this;
532
- fitTo(): string;
533
- fitTo(_: string): this;
534
-
535
- snapping(): string;
536
- snapping(_: string): this;
537
- snappingColumns(): number;
538
- snappingColumns(_: number): this;
539
- snappingRows(): number;
540
- snappingRows(_: number): this;
541
- snappingColumns_default(): number;
542
- snappingColumns_default(_: number): this;
543
- snappingRows_default(): number;
544
- snappingRows_default(_: number): this;
545
-
546
- gutter(): number;
547
- gutter(_: number): this;
548
-
549
- surfaceShadow(): boolean;
550
- surfaceShadow(_: boolean): this;
551
- surfacePadding(): string;
552
- surfacePadding(_: string): this;
553
- surfaceBorderWidth(): number;
554
- surfaceBorderWidth(_: number): this;
555
- surfaceBackgroundColor(): string;
556
- surfaceBackgroundColor(_: string): this;
557
-
558
- content(): Cell[];
559
- content(_: Cell[]): this;
560
- }
561
-
562
- Grid.prototype.publish("designMode", false, "boolean", "Design Mode", null, { tags: ["Basic"] });
563
- Grid.prototype.publish("showLanes", true, "boolean", "Show snapping lanes when in design mode", null, { tags: ["Basic"], disable: w => !w.designMode() });
564
- Grid.prototype.publish("fitTo", "all", "set", "Sizing Strategy", ["all", "width"], { tags: ["Basic"] });
565
- Grid.prototype.publish("snapping", "vertical", "set", "Snapping Strategy", ["vertical", "horizontal", "none"]);
566
- Grid.prototype.publish("snappingColumns", 12, "number", "Snapping Columns");
567
- Grid.prototype.publish("snappingRows", 16, "number", "Snapping Rows");
568
-
569
- Grid.prototype.publish("gutter", 6, "number", "Gap Between Widgets", null, { tags: ["Basic"] });
570
-
571
- Grid.prototype.publish("surfaceShadow", true, "boolean", "3D Shadow");
572
- Grid.prototype.publish("surfacePadding", null, "string", "Cell Padding (px)", null, { tags: ["Intermediate"] });
573
- Grid.prototype.publish("surfaceBorderWidth", 1, "number", "Width (px) of Cell Border", null, { tags: ["Intermediate"] });
574
- Grid.prototype.publish("surfaceBackgroundColor", null, "html-color", "Surface Background Color", null, { tags: ["Advanced"] });
575
-
576
- Grid.prototype.publish("content", [], "widgetArray", "widgets", null, { tags: ["Basic"], render: false });
1
+ import { d3Event, drag as d3Drag, HTMLWidget, Platform, select as d3Select, Utility } from "@hpcc-js/common";
2
+ import * as _GridList from "grid-list";
3
+ import { Cell } from "./Cell.ts";
4
+
5
+ import "../src/Grid.css";
6
+
7
+ const GridList = (_GridList && _GridList.default) || _GridList;
8
+
9
+ export type ICellPosition = [number, number, number, number];
10
+
11
+ export class Grid extends HTMLWidget {
12
+ divItems;
13
+
14
+ gridList;
15
+ items;
16
+ itemsMap;
17
+ origItems;
18
+ cellWidth;
19
+ cellHeight;
20
+ dragItem;
21
+ dragItemPos;
22
+
23
+ _d3Drag;
24
+ _d3DragResize;
25
+ _selectionBag;
26
+ _scrollBarWidth;
27
+
28
+ constructor() {
29
+ super();
30
+
31
+ this._tag = "div";
32
+ this._selectionBag = new Utility.Selection(this);
33
+
34
+ this.content([]);
35
+ }
36
+
37
+ getDimensions() {
38
+ const size = { width: 0, height: 0 };
39
+ this.content().forEach(function (cell) {
40
+ if (size.width < cell.gridCol() + cell.gridColSpan()) {
41
+ size.width = cell.gridCol() + cell.gridColSpan();
42
+ }
43
+ if (size.height < cell.gridRow() + cell.gridRowSpan()) {
44
+ size.height = cell.gridRow() + cell.gridRowSpan();
45
+ }
46
+ }, this);
47
+ return size;
48
+ }
49
+
50
+ clearContent(widget) {
51
+ this.content(this.content().filter(function (contentWidget) {
52
+ if (!widget) {
53
+ contentWidget.target(null);
54
+ return false;
55
+ }
56
+ let w: any = contentWidget;
57
+ while (w) {
58
+ if (widget === w) {
59
+ contentWidget.target(null);
60
+ return false;
61
+ }
62
+ w = w.widget ? w.widget() : null;
63
+ }
64
+ return true;
65
+ }));
66
+ }
67
+
68
+ setContent(row, col, widget, title?, rowSpan?, colSpan?) {
69
+ rowSpan = rowSpan || 1;
70
+ colSpan = colSpan || 1;
71
+ title = title || "";
72
+ this.content(this.content().filter(function (contentWidget) {
73
+ if (contentWidget.gridRow() === row && contentWidget.gridCol() === col) {
74
+ contentWidget.target(null);
75
+ return false;
76
+ }
77
+ return true;
78
+ }));
79
+ if (widget) {
80
+ const cell = new Cell()
81
+ .gridRow(row)
82
+ .gridCol(col)
83
+ .widget(widget)
84
+ .title(title)
85
+ .gridRowSpan(rowSpan)
86
+ .gridColSpan(colSpan)
87
+ ;
88
+ this.content().push(cell);
89
+ }
90
+ return this;
91
+ }
92
+
93
+ sortedContent() {
94
+ return this.content().sort(function (l, r) {
95
+ if (l.gridRow() === r.gridRow()) {
96
+ return l.gridCol() - r.gridCol();
97
+ }
98
+ return l.gridRow() - r.gridRow();
99
+ });
100
+ }
101
+
102
+ getCell(row, col) {
103
+ let retVal = null;
104
+ this.content().some(function (cell) {
105
+ if (row >= cell.gridRow() && row < cell.gridRow() + cell.gridRowSpan() &&
106
+ col >= cell.gridCol() && col < cell.gridCol() + cell.gridColSpan()) {
107
+ retVal = cell;
108
+ return true;
109
+ }
110
+ return false;
111
+ });
112
+ return retVal;
113
+ }
114
+
115
+ getWidgetCell(id) {
116
+ let retVal = null;
117
+ this.content().some(function (cell) {
118
+ if (cell.widget().id() === id) {
119
+ retVal = cell;
120
+ return true;
121
+ }
122
+ return false;
123
+ });
124
+ return retVal;
125
+ }
126
+
127
+ getContent(id) {
128
+ let retVal = null;
129
+ this.content().some(function (cell) {
130
+ if (cell.widget().id() === id) {
131
+ retVal = cell.widget();
132
+ return true;
133
+ }
134
+ return false;
135
+ });
136
+ return retVal;
137
+ }
138
+
139
+ cellToGridItem(cell) {
140
+ return {
141
+ x: cell.gridCol(),
142
+ y: cell.gridRow(),
143
+ w: cell.gridColSpan(),
144
+ h: cell.gridRowSpan(),
145
+ id: cell.id(),
146
+ cell
147
+ };
148
+ }
149
+
150
+ gridItemToCell(item) {
151
+ item.cell
152
+ .gridCol(item.x)
153
+ .gridRow(item.y)
154
+ .gridColSpan(item.w)
155
+ .gridRowSpan(item.h)
156
+ ;
157
+ }
158
+
159
+ resetItemsPos() {
160
+ this.origItems.forEach(function (origItem) {
161
+ const item = this.itemsMap[origItem.id];
162
+ item.x = origItem.x;
163
+ item.y = origItem.y;
164
+ }, this);
165
+ }
166
+
167
+ initGridList() {
168
+ this.itemsMap = {};
169
+ this.items = this.content().map(function (cell) {
170
+ const retVal = this.cellToGridItem(cell);
171
+ this.itemsMap[retVal.id] = retVal;
172
+ return retVal;
173
+ }, this);
174
+ this.origItems = this.content().map(this.cellToGridItem);
175
+ this.gridList = new GridList(this.items, {
176
+ direction: this.snapping(),
177
+ lanes: this.snapping() === "horizontal" ? this.snappingRows() : this.snappingColumns()
178
+ });
179
+ }
180
+
181
+ killGridList() {
182
+ this.gridList = null;
183
+ delete this.items;
184
+ delete this.itemsMap;
185
+ }
186
+
187
+ enter(domNode, element) {
188
+ super.enter(domNode, element);
189
+
190
+ this._scrollBarWidth = Platform.getScrollbarWidth();
191
+
192
+ const context = this;
193
+ this._d3Drag = d3Drag()
194
+ .subject(function (_d) {
195
+ const d = context.cellToGridItem(_d);
196
+ return { x: d.x * context.cellWidth, y: d.y * context.cellHeight };
197
+ })
198
+ .on("start", function (_d: any) {
199
+ if (!context.designMode()) return;
200
+ d3Event().sourceEvent.stopPropagation();
201
+ context.initGridList();
202
+ const d = context.itemsMap[_d.id()];
203
+ context.dragItem = element.append("div")
204
+ .attr("class", "dragging")
205
+ .style("transform", function () { return "translate(" + d.x * context.cellWidth + "px, " + d.y * context.cellHeight + "px)"; })
206
+ .style("width", function () { return d.w * context.cellWidth - context.gutter() + "px"; })
207
+ .style("height", function () { return d.h * context.cellHeight - context.gutter() + "px"; })
208
+ ;
209
+ context.selectionBagClick(_d);
210
+ })
211
+ .on("drag", function (_d: any) {
212
+ if (!context.designMode()) return;
213
+ const event = d3Event();
214
+ event.sourceEvent.stopPropagation();
215
+ const d = context.itemsMap[_d.id()];
216
+ if (event.x < 0) {
217
+ event.x = 0;
218
+ }
219
+ if (event.x + d.w * context.cellWidth > context.snappingColumns() * context.cellWidth) {
220
+ event.x = context.snappingColumns() * context.cellWidth - d.w * context.cellWidth;
221
+ }
222
+ if (event.y < 0) {
223
+ event.y = 0;
224
+ }
225
+ if (event.y + d.h * context.cellWidth > context.snappingRows() * context.cellWidth) {
226
+ event.y = context.snappingRows() * context.cellWidth - d.h * context.cellWidth;
227
+ }
228
+ const pos = [Math.max(0, Math.floor((event.x + context.cellWidth / 2) / context.cellWidth)), Math.max(0, Math.floor((event.y + context.cellHeight / 2) / context.cellHeight))];
229
+ if (d.x !== pos[0] || d.y !== pos[1]) {
230
+ if (context.snapping() !== "none") {
231
+ context.resetItemsPos();
232
+ context.gridList.moveItemToPosition(d, pos);
233
+ } else {
234
+ d.x = pos[0];
235
+ d.y = pos[1];
236
+ }
237
+ if (_d.gridCol() !== d.x || _d.gridRow() !== d.y) {
238
+ context.items.forEach(context.gridItemToCell);
239
+ context.updateGrid(false, 100);
240
+ }
241
+ }
242
+ context.dragItem
243
+ .style("transform", function () { return "translate(" + event.x + "px, " + event.y + "px)"; })
244
+ .style("width", function () { return d.w * context.cellWidth + "px"; })
245
+ .style("height", function () { return d.h * context.cellHeight + "px"; })
246
+ ;
247
+ })
248
+ .on("end", function () {
249
+ if (!context.designMode()) return;
250
+ d3Event().sourceEvent.stopPropagation();
251
+ context.dragItem.remove();
252
+ context.dragItem = null;
253
+ context.killGridList();
254
+ })
255
+ ;
256
+
257
+ this._d3DragResize = d3Drag()
258
+ .subject(function (_d) {
259
+ const d = context.cellToGridItem(_d);
260
+ return { x: (d.x + d.w - 1) * context.cellWidth, y: (d.y + d.h - 1) * context.cellHeight };
261
+ })
262
+ .on("start", function (_d: any) {
263
+ if (!context.designMode()) return;
264
+ d3Event().sourceEvent.stopPropagation();
265
+ context.initGridList();
266
+ const d = context.itemsMap[_d.id()];
267
+ context.dragItem = element.append("div")
268
+ .attr("class", "resizing")
269
+ .style("transform", function () { return "translate(" + d.x * context.cellWidth + "px, " + d.y * context.cellHeight + "px)"; })
270
+ .style("width", function () { return d.w * context.cellWidth - context.gutter() + "px"; })
271
+ .style("height", function () { return d.h * context.cellHeight - context.gutter() + "px"; })
272
+ ;
273
+ context.dragItemPos = { x: d.x, y: d.y };
274
+ })
275
+ .on("drag", function (_d: any) {
276
+ if (!context.designMode()) return;
277
+ const event = d3Event();
278
+ event.sourceEvent.stopPropagation();
279
+ const d = context.itemsMap[_d.id()];
280
+ const pos = [Math.max(0, Math.round(event.x / context.cellWidth)), Math.max(0, Math.round(event.y / context.cellHeight))];
281
+ const size = {
282
+ w: Math.max(1, pos[0] - d.x + 1),
283
+ h: Math.max(1, pos[1] - d.y + 1)
284
+ };
285
+ if (d.w !== size.w || d.h !== size.h) {
286
+ if (context.snapping() !== "none") {
287
+ context.resetItemsPos();
288
+ context.gridList.resizeItem(d, size);
289
+ } else {
290
+ d.w = size.w;
291
+ d.h = size.h;
292
+ }
293
+ if (_d.gridColSpan() !== d.w || _d.gridRowSpan() !== d.h) {
294
+ context.items.forEach(context.gridItemToCell);
295
+ context.updateGrid(d.id, 100);
296
+ }
297
+ }
298
+ context.dragItem
299
+ .style("width", function () { return (-d.x + 1) * context.cellWidth + event.x - context.gutter() + "px"; })
300
+ .style("height", function () { return (-d.y + 1) * context.cellHeight + event.y - context.gutter() + "px"; })
301
+ ;
302
+ })
303
+ .on("end", function () {
304
+ if (!context.designMode()) return;
305
+ d3Event().sourceEvent.stopPropagation();
306
+ context.dragItem.remove();
307
+ context.dragItem = null;
308
+ context.killGridList();
309
+ })
310
+ ;
311
+ }
312
+
313
+ updateGrid(resize, transitionDuration: number = 0, _noRender: boolean = false) {
314
+ transitionDuration = transitionDuration || 0;
315
+ const context = this;
316
+ this.divItems
317
+ .classed("draggable", this.designMode())
318
+ .transition().duration(transitionDuration)
319
+ .style("left", function (d) { return d.gridCol() * context.cellWidth + context.gutter() / 2 + "px"; })
320
+ .style("top", function (d) { return d.gridRow() * context.cellHeight + context.gutter() / 2 + "px"; })
321
+ .style("width", function (d) { return d.gridColSpan() * context.cellWidth - context.gutter() + "px"; })
322
+ .style("height", function (d) { return d.gridRowSpan() * context.cellHeight - context.gutter() + "px"; })
323
+ .on("end", function (d) {
324
+ d
325
+ .surfaceShadow_default(context.surfaceShadow())
326
+ .surfacePadding_default(context.surfacePadding())
327
+ .surfaceBorderWidth_default(context.surfaceBorderWidth())
328
+ .surfaceBackgroundColor_default(context.surfaceBackgroundColor())
329
+ ;
330
+
331
+ if (resize === true || resize === d.id()) {
332
+ d
333
+ .resize()
334
+ .lazyRender()
335
+ ;
336
+ }
337
+ })
338
+ ;
339
+ }
340
+
341
+ update(domNode, element2) {
342
+ super.update(domNode, element2);
343
+
344
+ this._placeholderElement.style("overflow-x", this.fitTo() === "width" ? "hidden" : null);
345
+ this._placeholderElement.style("overflow-y", this.fitTo() === "width" ? "scroll" : null);
346
+ const dimensions = this.getDimensions();
347
+ const clientWidth = this.width() - (this.fitTo() === "width" ? this._scrollBarWidth : 0);
348
+ this.cellWidth = clientWidth / dimensions.width;
349
+ this.cellHeight = this.fitTo() === "all" ? this.height() / dimensions.height : this.cellWidth;
350
+ if (this.designMode()) {
351
+ const cellLaneRatio = Math.min(this.width() / this.snappingColumns(), this.height() / this.snappingRows());
352
+ const laneWidth = Math.floor(cellLaneRatio);
353
+ this.cellWidth = laneWidth;
354
+ this.cellHeight = this.cellWidth;
355
+ }
356
+
357
+ // Grid ---
358
+ const context = this;
359
+ const divItems = element2.selectAll("#" + this.id() + " > .ddCell").data(this.content(), function (d) { return d.id(); });
360
+ this.divItems = divItems.enter().append("div")
361
+ .attr("class", "ddCell")
362
+ .each(function (d) {
363
+ d.target(this);
364
+ d.__grid_watch = d.monitor(function (key, newVal, oldVal) {
365
+ if (context._renderCount && (key === "snapping" || key.indexOf("grid") === 0) && newVal !== oldVal) {
366
+ if (!context.gridList) {
367
+ // API Call (only needed when not dragging) ---
368
+ context.initGridList();
369
+ if (context.snapping() !== "none") {
370
+ context.gridList.resizeGrid(context.snapping() === "horizontal" ? context.snappingRows() : context.snappingColumns());
371
+ }
372
+ context.items.forEach(context.gridItemToCell);
373
+ context.updateGrid(d.id(), 100);
374
+ context.killGridList();
375
+ }
376
+ }
377
+ });
378
+ const element = d3Select(this);
379
+ element.append("div")
380
+ .attr("class", "resizeHandle")
381
+ .call(context._d3DragResize)
382
+ .append("div")
383
+ .attr("class", "resizeHandleDisplay")
384
+ ;
385
+ }).merge(divItems)
386
+ ;
387
+ this.divItems.each(function (d) {
388
+ const element = d3Select(this);
389
+ if (context.designMode()) {
390
+ element.call(context._d3Drag);
391
+ } else {
392
+ element
393
+ .on("mousedown.drag", null)
394
+ .on("touchstart.drag", null)
395
+ ;
396
+ }
397
+ });
398
+ this.divItems.select(".resizeHandle")
399
+ .style("display", this.designMode() ? null : "none")
400
+ ;
401
+
402
+ this.updateGrid(true);
403
+ divItems.exit()
404
+ .each(function (d) {
405
+ d.target(null);
406
+ if (d.__grid_watch) {
407
+ d.__grid_watch.remove();
408
+ }
409
+ })
410
+ .remove()
411
+ ;
412
+
413
+ // Snapping ---
414
+ const lanesBackground = element2.selectAll("#" + this.id() + " > .laneBackground").data(this.designMode() ? [""] : []);
415
+ lanesBackground.enter().insert("div", ":first-child")
416
+ .attr("class", "laneBackground")
417
+ .style("left", "1px")
418
+ .style("top", "1px")
419
+ .on("click", function () {
420
+ context.selectionBagClear();
421
+ })
422
+ .merge(lanesBackground)
423
+ .style("width", (this.snappingColumns() * this.cellWidth) + "px")
424
+ .style("height", (this.snappingRows() * this.cellHeight) + "px")
425
+ ;
426
+ lanesBackground.exit()
427
+ .each(function () {
428
+ context.selectionBagClear();
429
+ })
430
+ .remove()
431
+ ;
432
+
433
+ const lanes = element2.selectAll("#" + this.id() + " > .lane").data(this.designMode() ? [""] : []);
434
+ lanes.enter().append("div")
435
+ .attr("class", "lane")
436
+ .style("left", "1px")
437
+ .style("top", "1px")
438
+ ;
439
+ lanes
440
+ .style("display", this.showLanes() ? null : "none")
441
+ .style("width", (this.snappingColumns() * this.cellWidth) + "px")
442
+ .style("height", (this.snappingRows() * this.cellHeight) + "px")
443
+ .style("background-image", "linear-gradient(to right, grey 1px, transparent 1px), linear-gradient(to bottom, grey 1px, transparent 1px)")
444
+ .style("background-size", this.cellWidth + "px " + this.cellHeight + "px")
445
+ ;
446
+ lanes.exit()
447
+ .remove()
448
+ ;
449
+ }
450
+
451
+ exit(domNode, element) {
452
+ this.content().forEach(w => w.target(null));
453
+ super.exit(domNode, element);
454
+ }
455
+
456
+ _createSelectionObject(d) {
457
+ return {
458
+ _id: d._id,
459
+ element: () => {
460
+ return d._element;
461
+ },
462
+ widget: d
463
+ };
464
+ }
465
+
466
+ selection(_) {
467
+ if (!arguments.length) return this._selectionBag.get().map(function (d) { return d._id; });
468
+ this._selectionBag.set(_.map(function (row) {
469
+ return this._createSelectionObject(row);
470
+ }, this));
471
+ return this;
472
+ }
473
+
474
+ selectionBagClear() {
475
+ if (!this._selectionBag.isEmpty()) {
476
+ this._selectionBag.clear();
477
+ this.postSelectionChange();
478
+ }
479
+ }
480
+
481
+ selectionBagClick(d) {
482
+ if (d !== null) {
483
+ const selectionObj = this._createSelectionObject(d);
484
+ if (d3Event().sourceEvent.ctrlKey) {
485
+ if (this._selectionBag.isSelected(selectionObj)) {
486
+ this._selectionBag.remove(selectionObj);
487
+ this.postSelectionChange();
488
+ } else {
489
+ this._selectionBag.append(selectionObj);
490
+ this.postSelectionChange();
491
+ }
492
+ } else {
493
+ const selected = this._selectionBag.get();
494
+ if (selected.length === 1 && selected[0]._id === selectionObj._id) {
495
+ this.selectionBagClear();
496
+ } else {
497
+ this._selectionBag.set([selectionObj]);
498
+ }
499
+ this.postSelectionChange();
500
+ }
501
+ }
502
+ }
503
+
504
+ postSelectionChange() {
505
+ }
506
+
507
+ applyLayout(layoutArr: ICellPosition[]) {
508
+ this.divItems.each((d, i) => {
509
+ if (layoutArr[i]) {
510
+ const [x, y, w, h] = layoutArr[i];
511
+ d
512
+ .gridCol(x)
513
+ .gridRow(y)
514
+ .gridColSpan(w)
515
+ .gridRowSpan(h)
516
+ ;
517
+ }
518
+ });
519
+ this.updateGrid(true);
520
+ }
521
+
522
+ vizActivation(elem) {
523
+ }
524
+ }
525
+ Grid.prototype._class += " layout_Grid";
526
+
527
+ export interface Grid {
528
+ designMode(): boolean;
529
+ designMode(_: boolean): this;
530
+ showLanes(): boolean;
531
+ showLanes(_: boolean): this;
532
+ fitTo(): string;
533
+ fitTo(_: string): this;
534
+
535
+ snapping(): string;
536
+ snapping(_: string): this;
537
+ snappingColumns(): number;
538
+ snappingColumns(_: number): this;
539
+ snappingRows(): number;
540
+ snappingRows(_: number): this;
541
+ snappingColumns_default(): number;
542
+ snappingColumns_default(_: number): this;
543
+ snappingRows_default(): number;
544
+ snappingRows_default(_: number): this;
545
+
546
+ gutter(): number;
547
+ gutter(_: number): this;
548
+
549
+ surfaceShadow(): boolean;
550
+ surfaceShadow(_: boolean): this;
551
+ surfacePadding(): string;
552
+ surfacePadding(_: string): this;
553
+ surfaceBorderWidth(): number;
554
+ surfaceBorderWidth(_: number): this;
555
+ surfaceBackgroundColor(): string;
556
+ surfaceBackgroundColor(_: string): this;
557
+
558
+ content(): Cell[];
559
+ content(_: Cell[]): this;
560
+ }
561
+
562
+ Grid.prototype.publish("designMode", false, "boolean", "Design Mode", null, { tags: ["Basic"] });
563
+ Grid.prototype.publish("showLanes", true, "boolean", "Show snapping lanes when in design mode", null, { tags: ["Basic"], disable: w => !w.designMode() });
564
+ Grid.prototype.publish("fitTo", "all", "set", "Sizing Strategy", ["all", "width"], { tags: ["Basic"] });
565
+ Grid.prototype.publish("snapping", "vertical", "set", "Snapping Strategy", ["vertical", "horizontal", "none"]);
566
+ Grid.prototype.publish("snappingColumns", 12, "number", "Snapping Columns");
567
+ Grid.prototype.publish("snappingRows", 16, "number", "Snapping Rows");
568
+
569
+ Grid.prototype.publish("gutter", 6, "number", "Gap Between Widgets", null, { tags: ["Basic"] });
570
+
571
+ Grid.prototype.publish("surfaceShadow", true, "boolean", "3D Shadow");
572
+ Grid.prototype.publish("surfacePadding", null, "string", "Cell Padding (px)", null, { tags: ["Intermediate"] });
573
+ Grid.prototype.publish("surfaceBorderWidth", 1, "number", "Width (px) of Cell Border", null, { tags: ["Intermediate"] });
574
+ Grid.prototype.publish("surfaceBackgroundColor", null, "html-color", "Surface Background Color", null, { tags: ["Advanced"] });
575
+
576
+ Grid.prototype.publish("content", [], "widgetArray", "widgets", null, { tags: ["Basic"], render: false });