mascot-vis 1.12.0 → 1.12.1
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/dist/mascot-min.d.ts +24350 -0
- package/dist/mascot-min.js +4 -4
- package/dist/mascot.js +1521 -1492
- package/package.json +5 -3
- package/scenes - toDel/AreaChart.msc +1 -0
- package/scenes - toDel/AreaChart2.msc +1 -0
- package/scenes - toDel/BarChartHorz.msc +1 -0
- package/scenes - toDel/BarChartVert.msc +1 -0
- package/scenes - toDel/BoxPlot.msc +1 -0
- package/scenes - toDel/BubblePlot.msc +1 -0
- package/scenes - toDel/BulletChart.msc +1 -0
- package/scenes - toDel/BumpChart.msc +1 -0
- package/scenes - toDel/CirclePacking.msc +1 -0
- package/scenes - toDel/ConnectedScatterPlot.msc +1 -0
- package/scenes - toDel/DensityPlot.msc +1 -0
- package/scenes - toDel/DivergingBarChart.msc +1 -0
- package/scenes - toDel/DotPlot.msc +1 -0
- package/scenes - toDel/DoughnutChart.msc +1 -0
- package/scenes - toDel/DumbbellChart.msc +1 -0
- package/scenes - toDel/GanttChart.msc +1 -0
- package/scenes - toDel/GridAreaChart.msc +1 -0
- package/scenes - toDel/GridStackedAreaChart.msc +1 -0
- package/scenes - toDel/GroupedBarChart.msc +1 -0
- package/scenes - toDel/HeatMap.msc +1 -0
- package/scenes - toDel/Histogram.msc +1 -0
- package/scenes - toDel/Isotype.msc +1 -0
- package/scenes - toDel/LineGraph.msc +1 -0
- package/scenes - toDel/LineGraph2.msc +1 -0
- package/scenes - toDel/LollipopChart.msc +1 -0
- package/scenes - toDel/MosaicPlot.msc +1 -0
- package/scenes - toDel/MultiLineGraph.msc +1 -0
- package/scenes - toDel/MultipleAreaCharts.msc +1 -0
- package/scenes - toDel/MultipleBarCharts.msc +1 -0
- package/scenes - toDel/MultipleBoxPlots.msc +1 -0
- package/scenes - toDel/MultiplePieCharts.msc +1 -0
- package/scenes - toDel/MultipleWaffleCharts.msc +1 -0
- package/scenes - toDel/ParallelCoordinates.msc +1 -0
- package/scenes - toDel/PieChart.msc +1 -0
- package/scenes - toDel/RadarChart.msc +1 -0
- package/scenes - toDel/RadialBarChart.msc +1 -0
- package/scenes - toDel/RangeChart.msc +1 -0
- package/scenes - toDel/RoseChart.msc +1 -0
- package/scenes - toDel/Scatterplot.msc +1 -0
- package/scenes - toDel/ScatterplotMatrix.msc +1 -0
- package/scenes - toDel/SlopeGraph.msc +1 -0
- package/scenes - toDel/Sparklines.msc +1 -0
- package/scenes - toDel/StackedAreaChart.msc +1 -0
- package/scenes - toDel/StackedBarChart.msc +1 -0
- package/scenes - toDel/StellarChart.msc +1 -0
- package/scenes - toDel/StreamGraph.msc +1 -0
- package/scenes - toDel/StringlineChart.msc +1 -0
- package/scenes - toDel/TowerChart.msc +1 -0
- package/scenes - toDel/Treemap.msc +1 -0
- package/scenes - toDel/ViolinPlot.msc +1 -0
- package/scenes - toDel/WaffleChart.msc +1 -0
- package/scenes - toDel/WaterfallChart.msc +1 -0
- package/scenes - toDel/ridgelinePlot.msc +1 -0
- package/scenes - toDel/test.msc +1 -0
package/dist/mascot.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
-
// version: 1.12.
|
|
2
|
+
// version: 1.12.1
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3'), require('pixi.js')) :
|
|
5
5
|
typeof define === 'function' && define.amd ? define(['exports', 'd3', 'pixi.js'], factory) :
|
|
@@ -257,7 +257,8 @@
|
|
|
257
257
|
FEATURE_NOT_IMPLEMENTED: "This feature has not been implemented yet",
|
|
258
258
|
LAYOUT_WITHOUT_TREE: "The layout can only be applied to a tree",
|
|
259
259
|
UNSUPPORTED_FIELDTYPE: "Unsupported field type for encoding ",
|
|
260
|
-
CANNOT_CLASSIFY: "Cannot classify items in "
|
|
260
|
+
CANNOT_CLASSIFY: "Cannot classify items in ",
|
|
261
|
+
CANNOT_CREATE_GLYPH: "Cannot create glyph. A glyph must consist of only paths or only texts, not a mixture of paths and texts"
|
|
261
262
|
};
|
|
262
263
|
|
|
263
264
|
const categoricalColorSchemes = [
|
|
@@ -272,1788 +273,1797 @@
|
|
|
272
273
|
"schemeBlues", "schemeGreens", "schemeGreys", "schemeOranges", "schemePurples", "schemeReds", "schemeBuGn", "schemeBuPu", "schemeGnBu", "schemeOrRd", "schemePuBuGn", "schemePuBu", "schemePuRd", "schemeRdPu", "schemeYlGnBu", "schemeYlGn", "schemeYlOrBr", "schemeYlOrRd"
|
|
273
274
|
];
|
|
274
275
|
|
|
275
|
-
class
|
|
276
|
+
class LinearGradient {
|
|
277
|
+
|
|
278
|
+
constructor(args) {
|
|
279
|
+
this._stops = [];
|
|
280
|
+
this.type = ItemType.LinearGradient;
|
|
281
|
+
this.id = this.type + ItemCounter[this.type]++;
|
|
282
|
+
this.x1 = ("x1" in args) ? args.x1 : 0;
|
|
283
|
+
this.x2 = ("x2" in args) ? args.x2 : 100;
|
|
284
|
+
this.y1 = ("y1" in args) ? args.y1 : 0;
|
|
285
|
+
this.y2 = ("y2" in args) ? args.y2 : 0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
toJSON() {
|
|
289
|
+
let json = {};
|
|
290
|
+
json.type = this.type;
|
|
291
|
+
json.id = this.id;
|
|
292
|
+
json.x1 = this.x1;
|
|
293
|
+
json.x2 = this.x2;
|
|
294
|
+
json.y1 = this.y1;
|
|
295
|
+
json.y2 = this.y2;
|
|
296
|
+
json.stops = this._stops;
|
|
297
|
+
return json;
|
|
298
|
+
}
|
|
276
299
|
|
|
277
|
-
|
|
278
|
-
this.
|
|
300
|
+
addStop(offset, color, opacity) {
|
|
301
|
+
this._stops.push({offset: offset, color: color, opacity: opacity});
|
|
279
302
|
}
|
|
280
303
|
|
|
281
|
-
|
|
304
|
+
get stops() {
|
|
305
|
+
return this._stops;
|
|
306
|
+
}
|
|
282
307
|
|
|
283
|
-
clone(){}
|
|
284
308
|
}
|
|
285
309
|
|
|
286
|
-
|
|
310
|
+
// Based on item.Item.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
311
|
+
|
|
312
|
+
class Mark {
|
|
287
313
|
|
|
288
314
|
constructor(args) {
|
|
289
|
-
|
|
290
|
-
this.
|
|
291
|
-
|
|
292
|
-
this.
|
|
293
|
-
this.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
315
|
+
this._dataScope = undefined;
|
|
316
|
+
this._id = undefined;
|
|
317
|
+
|
|
318
|
+
this.attrs = {};
|
|
319
|
+
this.styles = {};
|
|
320
|
+
this.staticProperties = {};
|
|
321
|
+
|
|
322
|
+
if (args !== undefined) {
|
|
323
|
+
for (let s in Style2SVG) {
|
|
324
|
+
if (s in args) {
|
|
325
|
+
this.styles[s] = args[s];
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
302
329
|
}
|
|
303
330
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
331
|
+
get id() {
|
|
332
|
+
return this._id;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
set id(id) {
|
|
336
|
+
if (this.getScene()){
|
|
337
|
+
delete this.getScene()._itemMap[this._id];
|
|
338
|
+
this._id = id;
|
|
339
|
+
this.getScene()._itemMap[id] = this;
|
|
340
|
+
} else {
|
|
341
|
+
this._id = id;
|
|
309
342
|
}
|
|
310
|
-
|
|
311
|
-
return false;
|
|
343
|
+
}
|
|
312
344
|
|
|
345
|
+
//TODO: implement winding contribution, see paper.js PathItem.Boolean.js
|
|
346
|
+
contains(px, py) {
|
|
347
|
+
if (!this._bounds)
|
|
348
|
+
return false;
|
|
349
|
+
if (!this._bounds.contains(px, py))
|
|
350
|
+
return false;
|
|
351
|
+
switch (this.type) {
|
|
352
|
+
case ItemType.Rect:
|
|
353
|
+
case ItemType.PointText:
|
|
354
|
+
return true;
|
|
355
|
+
case ItemType.Circle: {
|
|
356
|
+
let dist = Math.sqrt(Math.pow(px - this.x, 2) + Math.pow(py - this.y, 2));
|
|
357
|
+
return dist <= this.radius + this.strokeWidth;
|
|
358
|
+
}
|
|
359
|
+
case ItemType.Path: {
|
|
360
|
+
let ctx = CanvasProvider.getContext(),
|
|
361
|
+
p = new Path2D(this.getSVGPathData());
|
|
362
|
+
ctx.lineWidth = Math.max(this.strokeWidth, 2.5);
|
|
363
|
+
ctx.stroke(p);
|
|
364
|
+
if (this.closed) {
|
|
365
|
+
return ctx.isPointInPath(p, px, py);
|
|
366
|
+
} else {
|
|
367
|
+
return ctx.isPointInStroke(p, px, py);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
case ItemType.Line: {
|
|
371
|
+
let ctx = CanvasProvider.getContext(),
|
|
372
|
+
p = new Path2D(this.getSVGPathData());
|
|
373
|
+
ctx.lineWidth = Math.max(this.strokeWidth, 2.5);
|
|
374
|
+
ctx.stroke(p);
|
|
375
|
+
return ctx.isPointInStroke(p, px, py);
|
|
376
|
+
}
|
|
377
|
+
default: {
|
|
378
|
+
let ctx = CanvasProvider.getContext(),
|
|
379
|
+
p = new Path2D(this.getSVGPathData());
|
|
380
|
+
return ctx.isPointInPath(p, px, py);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
313
383
|
}
|
|
314
384
|
|
|
315
385
|
toJSON() {
|
|
316
|
-
let json = {
|
|
386
|
+
let json = {};
|
|
317
387
|
json.type = this.type;
|
|
318
|
-
json.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
json.args
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
388
|
+
json.id = this.id;
|
|
389
|
+
if (this.classId)
|
|
390
|
+
json.classId = this.classId;
|
|
391
|
+
if (this._dataScope)
|
|
392
|
+
json.dataScope = this._dataScope.toJSON();
|
|
393
|
+
json.args = {};
|
|
394
|
+
for (let s in this.attrs) {
|
|
395
|
+
json.args[s] = this.attrs[s];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
for (let s in this.styles) {
|
|
399
|
+
if (s.indexOf("Color") > 0 && this.styles[s] instanceof LinearGradient) {
|
|
400
|
+
json.args[s] = this.styles[s].toJSON();
|
|
401
|
+
} else {
|
|
402
|
+
json.args[s] = this.styles[s];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
327
405
|
return json;
|
|
328
406
|
}
|
|
329
407
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
rowGap: this._rowGap
|
|
339
|
-
});
|
|
408
|
+
getScene() {
|
|
409
|
+
let p = this;
|
|
410
|
+
while (p) {
|
|
411
|
+
if (p.type == ItemType.Scene)
|
|
412
|
+
return p;
|
|
413
|
+
else
|
|
414
|
+
p = p.parent;
|
|
415
|
+
}
|
|
340
416
|
}
|
|
341
417
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
numRows = this._numRows;
|
|
346
|
-
numCols = Math.ceil(this.group.children.length/this._numRows);
|
|
347
|
-
} else if (this._numCols) {
|
|
348
|
-
numCols = this._numCols;
|
|
349
|
-
numRows = Math.ceil(this.group.children.length/this._numCols);
|
|
350
|
-
}
|
|
418
|
+
set dataScope(ds) {
|
|
419
|
+
this._dataScope = ds;
|
|
420
|
+
}
|
|
351
421
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
422
|
+
get dataScope() {
|
|
423
|
+
return this._dataScope;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
duplicate() {
|
|
427
|
+
let scene = this.getScene();
|
|
428
|
+
let m = scene.mark(this.type);
|
|
429
|
+
this.copyPropertiesTo(m);
|
|
430
|
+
m.classId = this.classId;
|
|
431
|
+
if (this._dataScope) {
|
|
432
|
+
m._dataScope = this._dataScope.clone();
|
|
358
433
|
}
|
|
434
|
+
return m;
|
|
435
|
+
}
|
|
359
436
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
//TODO: cell size should be determined by the scale range extent if bound to data
|
|
366
|
-
//analyze the group's children to see if
|
|
367
|
-
|
|
368
|
-
let xEncs = group.getInternalEncodings("x"),
|
|
369
|
-
yEncs = group.getInternalEncodings("y"),
|
|
370
|
-
wdEncs = group.getInternalEncodings("width"),
|
|
371
|
-
htEncs = group.getInternalEncodings("height");
|
|
437
|
+
// eslint-disable-next-line no-unused-vars
|
|
438
|
+
_doTranslate(dx, dy){
|
|
439
|
+
//child classes have their own implementations
|
|
440
|
+
}
|
|
372
441
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
cellWidth = xEnc.scale.rangeExtent;
|
|
377
|
-
leftOffset = xEnc.scale.range[0];
|
|
378
|
-
if (xEnc.scale.type === "point") {
|
|
379
|
-
//TODO: need to handle variable sizes
|
|
380
|
-
cellWidth += xEnc.anyItem.bounds.width;
|
|
381
|
-
}
|
|
382
|
-
} else if (wdEncs.length > 0 && wdEncs[wdEncs.length -1]._rectNegativeValues) { //width encoding with negative values
|
|
383
|
-
cellWidth = wdEncs[wdEncs.length -1].scale.rangeExtent;
|
|
384
|
-
leftOffset = wdEncs[wdEncs.length -1].scale.range[0];
|
|
385
|
-
}
|
|
386
|
-
if (yEncs.length > 0) {
|
|
387
|
-
let yEnc = yEncs[yEncs.length -1];
|
|
388
|
-
cellHeight = yEnc.scale.rangeExtent;
|
|
389
|
-
if (yEnc.scale.type === "point") {
|
|
390
|
-
//TODO: need to handle variable sizes
|
|
391
|
-
cellHeight += yEnc.anyItem.bounds.height;
|
|
392
|
-
}
|
|
393
|
-
} else if (htEncs.length > 0 && htEncs[htEncs.length -1]._rectNegativeValues) { //width encoding with negative values
|
|
394
|
-
cellHeight = htEncs[htEncs.length -1].scale.rangeExtent;
|
|
395
|
-
}
|
|
442
|
+
set visibility(v) {
|
|
443
|
+
this.styles["visibility"] = v;
|
|
444
|
+
}
|
|
396
445
|
|
|
397
|
-
|
|
446
|
+
get visibility() {
|
|
447
|
+
if (!this.styles["visibility"])
|
|
448
|
+
return "visible";
|
|
449
|
+
return this.styles["visibility"];
|
|
450
|
+
}
|
|
398
451
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
for (let i = 0; i < cellCount; i++) {
|
|
404
|
-
cb.push(new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
405
|
-
this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
406
|
-
}
|
|
407
|
-
break;
|
|
408
|
-
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
409
|
-
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
410
|
-
case GridLayout.direction.Bottom2Top:
|
|
411
|
-
for (let i = 0; i < cellCount; i++) {
|
|
412
|
-
cb.push(new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
413
|
-
this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
414
|
-
}
|
|
415
|
-
break;
|
|
416
|
-
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
417
|
-
// this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
418
|
-
}
|
|
419
|
-
break;
|
|
420
|
-
case GridLayout.direction.Right2Left:
|
|
421
|
-
switch (this._dir[1]) {
|
|
422
|
-
case GridLayout.direction.Top2Bottom:
|
|
423
|
-
for (let i = 0; i < cellCount; i++) {
|
|
424
|
-
cb.push(new Rectangle(leftOffset + this._left + (numCols - 1) * (cellWidth + colGap) - (cellWidth + colGap) * (i%numCols),
|
|
425
|
-
this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
426
|
-
}
|
|
427
|
-
break;
|
|
428
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1) * (cellWidth + colGap) - (cellWidth + colGap) * (i%numCols),
|
|
429
|
-
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
430
|
-
case GridLayout.direction.Bottom2Top: {
|
|
431
|
-
for (let i = 0; i < cellCount; i++) {
|
|
432
|
-
cb.push(new Rectangle(leftOffset + this._left + (numCols - 1 - i%numCols) * (cellWidth + colGap),
|
|
433
|
-
this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
434
|
-
}
|
|
435
|
-
break;
|
|
436
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1 - i%numCols) * (cellWidth + colGap),
|
|
437
|
-
// this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
break;
|
|
441
|
-
case GridLayout.direction.Top2Bottom:
|
|
442
|
-
switch (this._dir[1]) {
|
|
443
|
-
case GridLayout.direction.Left2Right:
|
|
444
|
-
for (let i = 0; i < cellCount; i++) {
|
|
445
|
-
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
446
|
-
this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
447
|
-
}
|
|
448
|
-
break;
|
|
449
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
450
|
-
// this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
451
|
-
case GridLayout.direction.Right2Left:
|
|
452
|
-
for (let i = 0; i < cellCount; i++) {
|
|
453
|
-
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
454
|
-
this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
455
|
-
}
|
|
456
|
-
break;
|
|
457
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
458
|
-
// this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
459
|
-
}
|
|
460
|
-
break;
|
|
461
|
-
case GridLayout.direction.Bottom2Top:
|
|
462
|
-
switch (this._dir[1]) {
|
|
463
|
-
case GridLayout.direction.Left2Right:
|
|
464
|
-
for (let i = 0; i < cellCount; i++) {
|
|
465
|
-
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
466
|
-
this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
467
|
-
}
|
|
468
|
-
break;
|
|
469
|
-
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight)));
|
|
470
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
471
|
-
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
472
|
-
case GridLayout.direction.Right2Left:
|
|
473
|
-
for (let i = 0; i < cellCount; i++) {
|
|
474
|
-
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
475
|
-
this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
476
|
-
}
|
|
477
|
-
break;
|
|
478
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
479
|
-
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
480
|
-
}
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return cb;
|
|
485
|
-
|
|
486
|
-
// if (this._vDir == GridLayout.direction.Top2Bottom) {
|
|
487
|
-
// if (this._hDir == GridLayout.direction.Left2Right) {
|
|
488
|
-
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
489
|
-
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
490
|
-
// } else { //right to left
|
|
491
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1) * (cellWidth + colGap) - (cellWidth + colGap) * (i%numCols),
|
|
492
|
-
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
493
|
-
// }
|
|
494
|
-
// } else {
|
|
495
|
-
// let nr = Math.ceil(this.group.children.length/this._numCols);
|
|
496
|
-
// if (this._hDir == GridLayout.direction.Left2Right) {
|
|
497
|
-
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
498
|
-
// this._top + (nr - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
499
|
-
// } else {
|
|
500
|
-
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1 - i%numCols) * (cellWidth + colGap),
|
|
501
|
-
// this._top + (nr - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
502
|
-
// }
|
|
503
|
-
// }
|
|
452
|
+
get opacity() {
|
|
453
|
+
if (!("opacity" in this.styles))
|
|
454
|
+
return 1;
|
|
455
|
+
return this.styles["opacity"];
|
|
504
456
|
}
|
|
505
457
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
let cellBounds = this.cellBounds;
|
|
458
|
+
set opacity(c) {
|
|
459
|
+
this.styles["opacity"] = c;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
511
462
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
463
|
+
// Based on util.Numerical.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
464
|
+
// http://paperjs.org/
|
|
465
|
+
// Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey
|
|
466
|
+
// http://scratchdisk.com/ & https://puckey.studio/
|
|
467
|
+
//
|
|
468
|
+
// Distributed under the MIT license. See LICENSE file for detail
|
|
469
|
+
//
|
|
470
|
+
// All rights reserved.
|
|
519
471
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
472
|
+
/**
|
|
473
|
+
* A very small absolute value used to check if a value is very close to
|
|
474
|
+
* zero. The value should be large enough to offset any floating point
|
|
475
|
+
* noise, but small enough to be meaningful in computation in a nominal
|
|
476
|
+
* range (see MACHINE_EPSILON).
|
|
477
|
+
*
|
|
478
|
+
* http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
|
|
479
|
+
* http://www.cs.berkeley.edu/~wkahan/Math128/Cubic.pdf
|
|
480
|
+
*/
|
|
481
|
+
const EPSILON = 1e-12;
|
|
523
482
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
cdx = gridBound.left - c.bounds.left;
|
|
530
|
-
break;
|
|
531
|
-
case Alignment.Center:
|
|
532
|
-
cdx = gridBound.x - c.bounds.x;
|
|
533
|
-
break;
|
|
534
|
-
case Alignment.Right:
|
|
535
|
-
cdx = gridBound.right - c.bounds.right;
|
|
536
|
-
break;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (yEncs.length == 0) {
|
|
541
|
-
switch(this._cellVertAlignment) {
|
|
542
|
-
case Alignment.Top:
|
|
543
|
-
cdy = gridBound.top - c.bounds.top;
|
|
544
|
-
break;
|
|
545
|
-
case Alignment.Middle:
|
|
546
|
-
cdy = gridBound.y - c.bounds.y;
|
|
547
|
-
break;
|
|
548
|
-
case Alignment.Bottom:
|
|
549
|
-
cdy = gridBound.bottom - c.bounds.bottom;
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
c._doTranslate(cdx, cdy);
|
|
555
|
-
}
|
|
483
|
+
/**
|
|
484
|
+
* The epsilon to be used when performing "trigonometric" checks, such
|
|
485
|
+
* as examining cross products to check for collinearity.
|
|
486
|
+
*/
|
|
487
|
+
const TRIGONOMETRIC_EPSILON = 1e-8;
|
|
556
488
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
enc._apply();
|
|
565
|
-
}
|
|
566
|
-
}
|
|
489
|
+
/**
|
|
490
|
+
* Checks if the value is 0, within a tolerance defined by
|
|
491
|
+
* Numerical.EPSILON.
|
|
492
|
+
*/
|
|
493
|
+
function isZero(val) {
|
|
494
|
+
return val >= -EPSILON && val <= EPSILON;
|
|
495
|
+
}
|
|
567
496
|
|
|
568
|
-
|
|
569
|
-
//yEncs[yEncs.length-1]._map();
|
|
570
|
-
// yEncs[yEncs.length-1]._apply();
|
|
571
|
-
for (let enc of yEncs)
|
|
572
|
-
enc._apply();
|
|
573
|
-
} else if (htEncs.length > 0) {
|
|
574
|
-
let enc = htEncs[htEncs.length-1];
|
|
575
|
-
if (enc._rectNegativeValues){
|
|
576
|
-
enc._apply();
|
|
577
|
-
}
|
|
578
|
-
}
|
|
497
|
+
// Based on basic.Point.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
579
498
|
|
|
580
|
-
|
|
499
|
+
class Point {
|
|
500
|
+
|
|
501
|
+
constructor(x, y) {
|
|
502
|
+
this.x = x;
|
|
503
|
+
this.y = y;
|
|
581
504
|
}
|
|
582
505
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
this._rowGap = g;
|
|
586
|
-
this.run();
|
|
587
|
-
this.group.getScene()._relayoutAncestors(this.group);
|
|
506
|
+
transform(matrix) {
|
|
507
|
+
return matrix ? matrix._transformPoint(this) : this;
|
|
588
508
|
}
|
|
589
509
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
510
|
+
negate() {
|
|
511
|
+
return new Point(-this.x, -this.y);
|
|
512
|
+
}
|
|
593
513
|
|
|
594
|
-
|
|
595
|
-
this.
|
|
596
|
-
this.run();
|
|
597
|
-
this.group.getScene()._relayoutAncestors(this.group);
|
|
514
|
+
subtract(point) {
|
|
515
|
+
return new Point(this.x - point.x, this.y - point.y);
|
|
598
516
|
}
|
|
599
517
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
518
|
+
isZero() {
|
|
519
|
+
return isZero(this.x) && isZero(this.y)
|
|
520
|
+
}
|
|
603
521
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
522
|
+
/**
|
|
523
|
+
* Checks if the vector represented by this point is collinear (parallel) to
|
|
524
|
+
* another vector.
|
|
525
|
+
*
|
|
526
|
+
* @param {Point} point the vector to check against
|
|
527
|
+
* @return {Boolean} {@true it is collinear}
|
|
528
|
+
*/
|
|
529
|
+
isCollinear(point) {
|
|
530
|
+
let x1 = this.x,
|
|
531
|
+
y1 = this.y,
|
|
532
|
+
x2 = point.x,
|
|
533
|
+
y2 = point.y;
|
|
534
|
+
return Math.abs(x1 * y2 - y1 * x2) <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
|
|
535
|
+
* /*#=*/TRIGONOMETRIC_EPSILON;
|
|
536
|
+
}
|
|
614
537
|
|
|
615
|
-
|
|
616
|
-
if (this._numCols) {
|
|
617
|
-
return this._numCols;
|
|
618
|
-
} else if (this._numRows) {
|
|
619
|
-
return Math.ceil(this.group.children.length/this._numRows);
|
|
620
|
-
} else {
|
|
621
|
-
return 0;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
538
|
+
}
|
|
624
539
|
|
|
625
|
-
|
|
626
|
-
if (c < 0 || c > this.group.children.length) {
|
|
627
|
-
console.warn("Cannot set", c, "rows for", this.group.children.length, "items in grid");
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
this._numRows = c;
|
|
631
|
-
this._numCols = Math.ceil(this.group.children.length/c);
|
|
632
|
-
this.run();
|
|
633
|
-
this.group.getScene()._relayoutAncestors(this.group);
|
|
634
|
-
}
|
|
540
|
+
// Based on path.Segment.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
635
541
|
|
|
542
|
+
class Vertex {
|
|
636
543
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
544
|
+
//handles are relative to the point
|
|
545
|
+
constructor(point, parentMark, id) {
|
|
546
|
+
this.type = "vertex";
|
|
547
|
+
this._id = id;
|
|
548
|
+
this.x = point.x;
|
|
549
|
+
this.y = point.y;
|
|
550
|
+
this.dataScope = undefined;
|
|
551
|
+
this.parent = parentMark;
|
|
552
|
+
|
|
553
|
+
this.shape = undefined;
|
|
554
|
+
this.width = 0;
|
|
555
|
+
this.height = 0;
|
|
556
|
+
this.radius = 0;
|
|
557
|
+
this.fillColor = "#555";
|
|
558
|
+
this.opacity = 1;
|
|
559
|
+
this.strokeWidth = 0;
|
|
560
|
+
this.strokeColor = "#aaa";
|
|
561
|
+
this._polarAngle = undefined;
|
|
644
562
|
}
|
|
645
563
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
564
|
+
get bounds() {
|
|
565
|
+
switch(this.shape) {
|
|
566
|
+
case "rect":
|
|
567
|
+
return new Rectangle(this.x - this.width/2, this.y - this.height/2, this.width, this.height);
|
|
568
|
+
case "circle":
|
|
569
|
+
return new Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2);
|
|
570
|
+
default:
|
|
571
|
+
return new Rectangle(this.x - 0.5, this.y - 0.5, 1, 1);
|
|
649
572
|
}
|
|
650
|
-
this._cellVertAlignment = v;
|
|
651
|
-
this.run();
|
|
652
573
|
}
|
|
653
574
|
|
|
654
|
-
get
|
|
655
|
-
return this.
|
|
575
|
+
get id() {
|
|
576
|
+
return this.parent.id + "_v_" + this._id;
|
|
656
577
|
}
|
|
657
578
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
this.
|
|
579
|
+
toJSON() {
|
|
580
|
+
let json = {};
|
|
581
|
+
json.type = this.type;
|
|
582
|
+
json.id = this._id;
|
|
583
|
+
json.x = this.x;
|
|
584
|
+
json.y = this.y;
|
|
585
|
+
if (this.dataScope)
|
|
586
|
+
json.dataScope = this.dataScope.toJSON();
|
|
587
|
+
if (this._polarAngle !== undefined)
|
|
588
|
+
json.polarAngle = this._polarAngle;
|
|
589
|
+
json.shape = this.shape;
|
|
590
|
+
json.width = this.width;
|
|
591
|
+
json.height = this.height;
|
|
592
|
+
json.radius = this.radius;
|
|
593
|
+
json.fillColor = this.fillColor;
|
|
594
|
+
json.opacity = this.opacity;
|
|
595
|
+
json.strokeWidth = this.strokeWidth;
|
|
596
|
+
json.strokeColor = this.strokeColor;
|
|
597
|
+
return json;
|
|
664
598
|
}
|
|
665
599
|
|
|
666
|
-
|
|
667
|
-
|
|
600
|
+
static fromJSON(json, parent) {
|
|
601
|
+
let v = new Vertex(json, parent, json.id);
|
|
602
|
+
if (json.dataScope)
|
|
603
|
+
v.dataScope = json.dataScope;
|
|
604
|
+
if ("polarAngle" in json)
|
|
605
|
+
v.polarAngle = json.polarAngle;
|
|
606
|
+
v.shape = json.shape;
|
|
607
|
+
v.width = json.width;
|
|
608
|
+
v.height = json.height;
|
|
609
|
+
v.radius = json.radius;
|
|
610
|
+
v.fillColor = json.fillColor;
|
|
611
|
+
v.opacity = json.opacity;
|
|
612
|
+
v.strokeWidth = json.strokeWidth;
|
|
613
|
+
v.strokeColor = json.strokeColor;
|
|
614
|
+
return v;
|
|
668
615
|
}
|
|
669
616
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
617
|
+
_doTranslate(dx, dy) {
|
|
618
|
+
this.x += dx;
|
|
619
|
+
this.y += dy;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
_clone(parent) {
|
|
623
|
+
let v = new Vertex(new Point(this.x, this.y), parent, this._id);
|
|
624
|
+
if (this.dataScope) {
|
|
625
|
+
v.dataScope = this.dataScope.clone();
|
|
676
626
|
}
|
|
677
|
-
this.
|
|
627
|
+
v.shape = this.shape;
|
|
628
|
+
v.width = this.width;
|
|
629
|
+
v.height = this.height;
|
|
630
|
+
v.radius = this.radius;
|
|
631
|
+
v.fillColor = this.fillColor;
|
|
632
|
+
v.opacity = this.opacity;
|
|
633
|
+
v.strokeWidth = this.strokeWidth;
|
|
634
|
+
v.strokeColor = this.strokeColor;
|
|
635
|
+
return v;
|
|
678
636
|
}
|
|
679
637
|
|
|
680
|
-
|
|
681
|
-
|
|
638
|
+
set polarAngle(a) {
|
|
639
|
+
this._polarAngle = a;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
get polarAngle() {
|
|
643
|
+
return this._polarAngle;
|
|
682
644
|
}
|
|
683
645
|
}
|
|
684
646
|
|
|
685
|
-
|
|
686
|
-
Left2Right: "l2r",
|
|
687
|
-
Right2Left: "r2l",
|
|
688
|
-
Top2Bottom: "t2b",
|
|
689
|
-
Bottom2Top: "b2t"
|
|
690
|
-
};
|
|
647
|
+
Vertex.styles = ["vxShape", "vxWidth", "vxHeight", "vxRadius", "vxFillColor", "vxStrokeColor", "vxStrokeWidth", "vxOpacity"];
|
|
691
648
|
|
|
692
|
-
class
|
|
649
|
+
class Segment {
|
|
693
650
|
|
|
694
|
-
constructor(
|
|
695
|
-
this.
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
651
|
+
constructor(v1, v2, parentMark, id) {
|
|
652
|
+
this.type = "segment";
|
|
653
|
+
this._id = id;
|
|
654
|
+
this.vertex1 = v1;
|
|
655
|
+
this.vertex2 = v2;
|
|
656
|
+
|
|
657
|
+
this.dataScope = undefined;
|
|
658
|
+
this.parent = parentMark;
|
|
702
659
|
}
|
|
703
|
-
|
|
704
|
-
toJSON() {
|
|
705
|
-
let json = {};
|
|
706
|
-
json.type = this.type;
|
|
707
|
-
json.id = this.id;
|
|
708
|
-
json.x1 = this.x1;
|
|
709
|
-
json.x2 = this.x2;
|
|
710
|
-
json.y1 = this.y1;
|
|
711
|
-
json.y2 = this.y2;
|
|
712
|
-
json.stops = this._stops;
|
|
713
|
-
return json;
|
|
714
|
-
}
|
|
715
660
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
661
|
+
get id() {
|
|
662
|
+
return this.parent.id + "_s_" + this._id;
|
|
663
|
+
}
|
|
719
664
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
665
|
+
_doTranslate(dx, dy) {
|
|
666
|
+
this.vertex1._doTranslate(dx, dy);
|
|
667
|
+
this.vertex2._doTranslate(dx, dy);
|
|
668
|
+
}
|
|
723
669
|
|
|
670
|
+
get x() {
|
|
671
|
+
return (this.vertex1.x + this.vertex2.x)/2;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
get y() {
|
|
675
|
+
return (this.vertex1.y + this.vertex2.y)/2;
|
|
676
|
+
}
|
|
724
677
|
}
|
|
725
678
|
|
|
726
|
-
|
|
679
|
+
class Path extends Mark {
|
|
680
|
+
|
|
681
|
+
constructor(args) {
|
|
682
|
+
super(args);
|
|
683
|
+
this.type = "type" in args ? args.type : ItemType.Path;
|
|
727
684
|
|
|
728
|
-
|
|
685
|
+
if (!("strokeColor" in this.styles))
|
|
686
|
+
this.styles["strokeColor"] = "#ccc";
|
|
687
|
+
if (!("strokeWidth" in this.styles))
|
|
688
|
+
this.styles["strokeWidth"] = 1;
|
|
689
|
+
if (!("strokeDash" in this.styles))
|
|
690
|
+
this.styles["strokeDash"] = "none";
|
|
729
691
|
|
|
730
|
-
|
|
731
|
-
this.
|
|
732
|
-
this.
|
|
692
|
+
this.vertices = [];
|
|
693
|
+
this.vertexCounter = 0; //for assigning vertex ids
|
|
694
|
+
this.segmentCounter = 0;
|
|
695
|
+
this.segments = [];
|
|
733
696
|
|
|
734
|
-
this.
|
|
735
|
-
|
|
736
|
-
this.
|
|
697
|
+
this.anchor = undefined;
|
|
698
|
+
|
|
699
|
+
this.closed = false;
|
|
700
|
+
|
|
701
|
+
this.curveMode = "linear";
|
|
702
|
+
|
|
703
|
+
//when a path encodes data using its width or height, its geometric bounds may not be the same as its orginal bounds without encoding applied
|
|
704
|
+
this.boundsOffsets = {top: 0, bottom: 0, left: 0, right: 0};
|
|
705
|
+
|
|
706
|
+
this._vxShape = undefined;
|
|
707
|
+
this._vxWidth = 0;
|
|
708
|
+
this._vxHeight = 0;
|
|
709
|
+
this._vxRadius = 0;
|
|
710
|
+
this._vxFillColor = "#555555";
|
|
711
|
+
this._vxStrokeColor = "#aaaaaa";
|
|
712
|
+
this._vxStrokeWidth = 0;
|
|
713
|
+
this._vxOpacity = 1;
|
|
737
714
|
|
|
738
715
|
if (args !== undefined) {
|
|
739
|
-
for (let
|
|
740
|
-
if (
|
|
741
|
-
this
|
|
742
|
-
}
|
|
716
|
+
for (let vs of Vertex.styles){
|
|
717
|
+
if (vs in args)
|
|
718
|
+
this["_" + vs] = args[vs];
|
|
743
719
|
}
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
720
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
set id(id) {
|
|
752
|
-
if (this.getScene()){
|
|
753
|
-
delete this.getScene()._itemMap[this._id];
|
|
754
|
-
this._id = id;
|
|
755
|
-
this.getScene()._itemMap[id] = this;
|
|
756
|
-
} else {
|
|
757
|
-
this._id = id;
|
|
721
|
+
if ("vertices" in args) {
|
|
722
|
+
this._setVertices(args["vertices"]);
|
|
723
|
+
}
|
|
758
724
|
}
|
|
759
725
|
}
|
|
760
726
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (!this._bounds.contains(px, py))
|
|
766
|
-
return false;
|
|
727
|
+
toJSON() {
|
|
728
|
+
let json = super.toJSON();
|
|
729
|
+
json.type = this.type;
|
|
730
|
+
json.id = this.id;
|
|
767
731
|
switch (this.type) {
|
|
768
732
|
case ItemType.Rect:
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
733
|
+
json.args.width = this.width;
|
|
734
|
+
json.args.height = this.height;
|
|
735
|
+
json.args.top = this.top;
|
|
736
|
+
json.args.left = this.left;
|
|
737
|
+
break;
|
|
738
|
+
case ItemType.Circle:
|
|
739
|
+
json.args.x = this.x;
|
|
740
|
+
json.args.y = this.y;
|
|
741
|
+
json.args.radius = this.radius;
|
|
742
|
+
break;
|
|
743
|
+
case ItemType.Arc:
|
|
744
|
+
case ItemType.Pie:
|
|
745
|
+
json.args.x = this._x;
|
|
746
|
+
json.args.y = this._y;
|
|
747
|
+
json.args.innerRadius = this._innerRadius;
|
|
748
|
+
json.args.outerRadius = this._outerRadius;
|
|
749
|
+
json.args.startAngle = this._startAngle;
|
|
750
|
+
json.args.endAngle = this._endAngle;
|
|
751
|
+
break;
|
|
752
|
+
default:
|
|
753
|
+
json.vertices = [];
|
|
754
|
+
for (let v of this.vertices)
|
|
755
|
+
json.vertices.push(v.toJSON());
|
|
756
|
+
if (this.type === ItemType.Polygon) {
|
|
757
|
+
json.args.x = this._x;
|
|
758
|
+
json.args.y = this._y;
|
|
759
|
+
json.args.radius = this._radius;
|
|
760
|
+
} else if (this.type === ItemType.Area) {
|
|
761
|
+
json.args.baseline = this._baseline;
|
|
762
|
+
json.args.orientation = this._orientation;
|
|
784
763
|
}
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
// if (this.type === ItemType.Rect) {
|
|
767
|
+
// json.args.width = this.width;
|
|
768
|
+
// json.args.height = this.height;
|
|
769
|
+
// json.args.top = this.top;
|
|
770
|
+
// json.args.left = this.left;
|
|
771
|
+
// } else if (this.type === ItemType.Circle) {
|
|
772
|
+
// json.args.x = this.x;
|
|
773
|
+
// json.args.y = this.y;
|
|
774
|
+
// json.args.radius = this.radius;
|
|
775
|
+
// } else if (this.type === ItemType.Arc) {
|
|
776
|
+
// json.args.x = this._x;
|
|
777
|
+
// json.args.y = this._y;
|
|
778
|
+
// json.args.innerRadius = this._innerRadius;
|
|
779
|
+
// json.args.outerRadius = this._outerRadius;
|
|
780
|
+
// json.args.startAngle = this._startAngle;
|
|
781
|
+
// json.args.endAngle = this._endAngle;
|
|
782
|
+
// } else if (this.type === ItemType.Pie) {
|
|
783
|
+
// json.args.x = this._x;
|
|
784
|
+
// json.args.y = this._y;
|
|
785
|
+
// json.args.radius = this.radius;
|
|
786
|
+
// json.args.startAngle = this.startAngleDeg;
|
|
787
|
+
// json.args.endAngle = this.endAngleDeg;
|
|
788
|
+
// } else {
|
|
789
|
+
// json.vertices = [];
|
|
790
|
+
// for (let v of this.vertices)
|
|
791
|
+
// json.vertices.push(v.toJSON());
|
|
792
|
+
// if (this.type === ItemType.Polygon) {
|
|
793
|
+
// json.args.x = this._x;
|
|
794
|
+
// json.args.y = this._y;
|
|
795
|
+
// json.args.radius = this._radius;
|
|
796
|
+
// } else if (this.type === ItemType.Area) {
|
|
797
|
+
// json.args.baseline = this._baseline;
|
|
798
|
+
// json.args.orientation = this._orientation;
|
|
799
|
+
// }
|
|
800
|
+
// }
|
|
801
|
+
json.vertexCounter = this.vertexCounter;
|
|
802
|
+
json.segmentCounter = this.segmentCounter;
|
|
803
|
+
//do not save segments, anchor and closed for now
|
|
804
|
+
json.curveMode = this.curveMode;
|
|
805
|
+
if (this._bounds)
|
|
806
|
+
json.bounds = this._bounds.toJSON();
|
|
807
|
+
json.boundsOffsets = this.boundsOffsets;
|
|
808
|
+
for (let s of Vertex.styles) {
|
|
809
|
+
json.args[s] = this[s];
|
|
810
|
+
}
|
|
811
|
+
return json;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
_setVertices(vertices) {
|
|
815
|
+
let vertex, point;
|
|
816
|
+
this.vertices = [];
|
|
817
|
+
this.segments = [];
|
|
818
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
819
|
+
|
|
820
|
+
if (i == vertices.length - 1 && vertices[i][0] === vertices[0][0] && vertices[i][1] === vertices[0][1] && this.type === ItemType.Path) {
|
|
821
|
+
continue;
|
|
785
822
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
return ctx.isPointInPath(p, px, py);
|
|
823
|
+
|
|
824
|
+
point = new Point(vertices[i][0], vertices[i][1]);
|
|
825
|
+
|
|
826
|
+
vertex = new Vertex(point, this, this.vertexCounter++);
|
|
827
|
+
|
|
828
|
+
for (let vs of Vertex.styles){
|
|
829
|
+
if (this[vs]){
|
|
830
|
+
let temp = vs.replace("vx", "");
|
|
831
|
+
vertex[temp[0].toLowerCase() + temp.slice(1)] = this[vs];
|
|
832
|
+
}
|
|
797
833
|
}
|
|
834
|
+
|
|
835
|
+
this.vertices.push(vertex);
|
|
836
|
+
if (i > 0)
|
|
837
|
+
this.segments.push(new Segment(this.vertices[i-1], this.vertices[i], this, this.segmentCounter++));
|
|
838
|
+
}
|
|
839
|
+
//if the first vertex has the same position as the last, this path is closed
|
|
840
|
+
let first = vertices[0], last = vertices[vertices.length - 1];
|
|
841
|
+
if ((first[0] === last[0] && first[1] === last[1]) || this.type === ItemType.Rect) {
|
|
842
|
+
this.closed = true;
|
|
843
|
+
if (!("fillColor" in this.styles))
|
|
844
|
+
this.styles["fillColor"] = "#fff";
|
|
845
|
+
this.segments.push(new Segment(this.vertices[this.vertices.length-1], this.vertices[0], this, this.segmentCounter++));
|
|
798
846
|
}
|
|
799
847
|
}
|
|
800
848
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
849
|
+
copyPropertiesTo(target) {
|
|
850
|
+
target.attrs = Object.assign({}, this.attrs);
|
|
851
|
+
target.styles = Object.assign({}, this.styles);
|
|
852
|
+
for (let vs of Vertex.styles){
|
|
853
|
+
if (this["_"+vs])
|
|
854
|
+
target["_"+vs] = this["_"+vs];
|
|
855
|
+
}
|
|
807
856
|
if (this._dataScope)
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
857
|
+
target._dataScope = this._dataScope.clone();
|
|
858
|
+
target.closed = this.closed;
|
|
859
|
+
target.curveMode = this.curveMode;
|
|
860
|
+
target.vertices = [];
|
|
861
|
+
target.segments = [];
|
|
862
|
+
for (let v of this.vertices) {
|
|
863
|
+
target.vertices.push(v._clone(target));
|
|
812
864
|
}
|
|
813
|
-
|
|
814
|
-
for (let
|
|
815
|
-
|
|
816
|
-
json.args[s] = this.styles[s].toJSON();
|
|
817
|
-
} else {
|
|
818
|
-
json.args[s] = this.styles[s];
|
|
819
|
-
}
|
|
865
|
+
target.segmentCounter = 0;
|
|
866
|
+
for (let i = 1; i < target.vertices.length; i++) {
|
|
867
|
+
target.segments.push(new Segment(target.vertices[i-1], target.vertices[i], target, target.segmentCounter++));
|
|
820
868
|
}
|
|
821
|
-
|
|
869
|
+
if (target.closed)
|
|
870
|
+
target.segments.push(new Segment(target.vertices[target.vertices.length-1], target.vertices[0], target, target.segmentCounter++));
|
|
822
871
|
}
|
|
823
872
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
873
|
+
/*
|
|
874
|
+
* returns the bounds without incorporating transformations involving rotation
|
|
875
|
+
*/
|
|
876
|
+
get bounds() {
|
|
877
|
+
if (!this._bounds)
|
|
878
|
+
this._updateBounds();
|
|
879
|
+
return this._bounds;
|
|
832
880
|
}
|
|
833
881
|
|
|
834
|
-
|
|
835
|
-
|
|
882
|
+
/**
|
|
883
|
+
* return the bounds as if the path does not encode data
|
|
884
|
+
*/
|
|
885
|
+
get refBounds() {
|
|
886
|
+
if (!this._bounds)
|
|
887
|
+
this._updateBounds();
|
|
888
|
+
let ht = (this._bounds.bottom + this.boundsOffsets.bottom) - (this._bounds.top - this.boundsOffsets.top),
|
|
889
|
+
wd = this._bounds.right + this.boundsOffsets.right - (this._bounds.left - this.boundsOffsets.left);
|
|
890
|
+
return new Rectangle(this._bounds.left - this.boundsOffsets.left, this._bounds.top - this.boundsOffsets.top, wd, ht);
|
|
836
891
|
}
|
|
837
892
|
|
|
838
|
-
get
|
|
839
|
-
return this.
|
|
893
|
+
get x() {
|
|
894
|
+
return this.bounds.x;
|
|
840
895
|
}
|
|
841
896
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
let m = scene.mark(this.type);
|
|
845
|
-
this.copyPropertiesTo(m);
|
|
846
|
-
m.classId = this.classId;
|
|
847
|
-
if (this._dataScope) {
|
|
848
|
-
m._dataScope = this._dataScope.clone();
|
|
849
|
-
}
|
|
850
|
-
return m;
|
|
897
|
+
get y() {
|
|
898
|
+
return this.bounds.y;
|
|
851
899
|
}
|
|
852
900
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
//child classes have their own implementations
|
|
901
|
+
get strokeColor() {
|
|
902
|
+
return this.styles["strokeColor"];
|
|
856
903
|
}
|
|
857
904
|
|
|
858
|
-
set
|
|
859
|
-
this.styles["
|
|
905
|
+
set strokeColor(c) {
|
|
906
|
+
this.styles["strokeColor"] = c;
|
|
860
907
|
}
|
|
861
908
|
|
|
862
|
-
get
|
|
863
|
-
|
|
864
|
-
return "visible";
|
|
865
|
-
return this.styles["visibility"];
|
|
909
|
+
get strokeWidth() {
|
|
910
|
+
return this.styles["strokeWidth"];
|
|
866
911
|
}
|
|
867
912
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
return 1;
|
|
871
|
-
return this.styles["opacity"];
|
|
913
|
+
set strokeWidth(c) {
|
|
914
|
+
this.styles["strokeWidth"] = c;
|
|
872
915
|
}
|
|
873
916
|
|
|
874
|
-
|
|
875
|
-
this.styles["
|
|
917
|
+
get fillColor() {
|
|
918
|
+
return this.styles["fillColor"];
|
|
876
919
|
}
|
|
877
|
-
}
|
|
878
920
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
// http://scratchdisk.com/ & https://puckey.studio/
|
|
883
|
-
//
|
|
884
|
-
// Distributed under the MIT license. See LICENSE file for detail
|
|
885
|
-
//
|
|
886
|
-
// All rights reserved.
|
|
921
|
+
set fillColor(c) {
|
|
922
|
+
this.styles["fillColor"] = c;
|
|
923
|
+
}
|
|
887
924
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
* noise, but small enough to be meaningful in computation in a nominal
|
|
892
|
-
* range (see MACHINE_EPSILON).
|
|
893
|
-
*
|
|
894
|
-
* http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
|
|
895
|
-
* http://www.cs.berkeley.edu/~wkahan/Math128/Cubic.pdf
|
|
896
|
-
*/
|
|
897
|
-
const EPSILON = 1e-12;
|
|
925
|
+
get strokeDash() {
|
|
926
|
+
return this.styles["strokeDash"];
|
|
927
|
+
}
|
|
898
928
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
*/
|
|
903
|
-
const TRIGONOMETRIC_EPSILON = 1e-8;
|
|
929
|
+
set strokeDash(c) {
|
|
930
|
+
this.styles["strokeDash"] = c;
|
|
931
|
+
}
|
|
904
932
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
}
|
|
933
|
+
_doTranslate(dx, dy) {
|
|
934
|
+
for (let v of this.vertices) {
|
|
935
|
+
v._doTranslate(dx, dy);
|
|
936
|
+
}
|
|
937
|
+
this._updateBounds();
|
|
938
|
+
}
|
|
912
939
|
|
|
913
|
-
|
|
940
|
+
//by default, with respect to the center of bounds
|
|
941
|
+
resize(wd, ht, xRef, yRef) {
|
|
942
|
+
let bounds = this.bounds, bWidth = bounds.width === 0 ? 1 : bounds.width, bHeight = bounds.height === 0 ? 1 : bounds.height;
|
|
943
|
+
if (xRef === "right") {
|
|
944
|
+
for (let v of this.vertices) {
|
|
945
|
+
v.x = bounds.right - (wd/bWidth) * (bounds.right - v.x);
|
|
946
|
+
}
|
|
947
|
+
} else {
|
|
948
|
+
for (let v of this.vertices) {
|
|
949
|
+
v.x = bounds.left + (wd/bWidth) * (v.x - bounds.left);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (yRef === "top") {
|
|
953
|
+
for (let v of this.vertices) {
|
|
954
|
+
v.y = bounds.top + (ht/bHeight) * (v.y - bounds.top);
|
|
955
|
+
}
|
|
956
|
+
} else {
|
|
957
|
+
for (let v of this.vertices) {
|
|
958
|
+
v.y = bounds.bottom - (ht/bHeight) * (bounds.bottom - v.y);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
this._updateBounds();
|
|
962
|
+
}
|
|
914
963
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
964
|
+
_updateBounds() {
|
|
965
|
+
let vx = this.vertices.map(d => d.x),
|
|
966
|
+
vy = this.vertices.map(d => d.y);
|
|
967
|
+
|
|
968
|
+
let left = Math.min(...vx), top = Math.min(...vy), right = Math.max(...vx), btm = Math.max(...vy);
|
|
969
|
+
|
|
970
|
+
this._bounds = new Rectangle(left, top, right - left, btm - top);
|
|
971
|
+
if (this.type === ItemType.Line || this.type === ItemType.Path) {
|
|
972
|
+
let sw = this.styles["strokeWidth"] ? this.styles["strokeWidth"] : 1;
|
|
973
|
+
if (left === right)
|
|
974
|
+
this._bounds = new Rectangle(left - sw/2, top, right - left + sw, btm - top);
|
|
975
|
+
else if (top === btm)
|
|
976
|
+
this._bounds = new Rectangle(left, top - sw/2, right - left, btm - top + sw);
|
|
977
|
+
}
|
|
920
978
|
}
|
|
921
979
|
|
|
922
|
-
|
|
923
|
-
|
|
980
|
+
addVertex(x, y, i) {
|
|
981
|
+
let vertex = new Vertex(new Point(x, y), this, this.vertexCounter++);
|
|
982
|
+
this.vertices.splice(i, 0, vertex);
|
|
983
|
+
//TODO: handle segments
|
|
924
984
|
}
|
|
925
985
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
986
|
+
sortVertices(channel, descending) {
|
|
987
|
+
this.vertices.sort((a,b) => a[channel] - b[channel]);
|
|
988
|
+
if (descending)
|
|
989
|
+
this.vertices.reverse();
|
|
990
|
+
for (let i = 0; i < this.segments.length; i++) {
|
|
991
|
+
let segment = this.segments[i];
|
|
992
|
+
segment.vertex1 = this.vertices[i];
|
|
993
|
+
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
994
|
+
}
|
|
995
|
+
}
|
|
929
996
|
|
|
930
|
-
|
|
931
|
-
|
|
997
|
+
sortVerticesByData(field, descending, order) {
|
|
998
|
+
let f;
|
|
999
|
+
if (order)
|
|
1000
|
+
f = (a, b) => order.indexOf(a.dataScope.getFieldValue(field)) - order.indexOf(b.dataScope.getFieldValue(field));
|
|
1001
|
+
else
|
|
1002
|
+
f = (a, b) => (a.dataScope.getFieldValue(field) < b.dataScope.getFieldValue(field) ? -1 : 1 );
|
|
1003
|
+
this.vertices.sort(f);
|
|
1004
|
+
if (descending)
|
|
1005
|
+
this.vertices.reverse();
|
|
1006
|
+
for (let i = 0; i < this.segments.length; i++) {
|
|
1007
|
+
let segment = this.segments[i];
|
|
1008
|
+
segment.vertex1 = this.vertices[i];
|
|
1009
|
+
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
1010
|
+
}
|
|
932
1011
|
}
|
|
933
1012
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1013
|
+
getSVGPathData() {
|
|
1014
|
+
let p = d3__namespace.path();
|
|
1015
|
+
let curve = this._getD3CurveFunction(this.curveMode)(p);
|
|
1016
|
+
curve.lineStart();
|
|
1017
|
+
for (let vertex of this.vertices) {
|
|
1018
|
+
curve.point(vertex.x, vertex.y);
|
|
1019
|
+
}
|
|
1020
|
+
if (this.closed)
|
|
1021
|
+
curve.point(this.vertices[0].x, this.vertices[0].y);
|
|
1022
|
+
curve.lineEnd();
|
|
937
1023
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
* @param {Point} point the vector to check against
|
|
943
|
-
* @return {Boolean} {@true it is collinear}
|
|
944
|
-
*/
|
|
945
|
-
isCollinear(point) {
|
|
946
|
-
let x1 = this.x,
|
|
947
|
-
y1 = this.y,
|
|
948
|
-
x2 = point.x,
|
|
949
|
-
y2 = point.y;
|
|
950
|
-
return Math.abs(x1 * y2 - y1 * x2) <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
|
|
951
|
-
* /*#=*/TRIGONOMETRIC_EPSILON;
|
|
952
|
-
}
|
|
1024
|
+
return p._;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// toSVG() {
|
|
953
1028
|
|
|
954
|
-
|
|
1029
|
+
// }
|
|
955
1030
|
|
|
956
|
-
|
|
1031
|
+
// fromSVG() {
|
|
957
1032
|
|
|
958
|
-
|
|
1033
|
+
// }
|
|
959
1034
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
this._id = id;
|
|
964
|
-
this.x = point.x;
|
|
965
|
-
this.y = point.y;
|
|
966
|
-
this.dataScope = undefined;
|
|
967
|
-
this.parent = parentMark;
|
|
1035
|
+
get firstVertex() {
|
|
1036
|
+
return this.vertices[0];
|
|
1037
|
+
}
|
|
968
1038
|
|
|
969
|
-
|
|
970
|
-
this.
|
|
971
|
-
this.height = 0;
|
|
972
|
-
this.radius = 0;
|
|
973
|
-
this.fillColor = "#555";
|
|
974
|
-
this.opacity = 1;
|
|
975
|
-
this.strokeWidth = 0;
|
|
976
|
-
this.strokeColor = "#aaa";
|
|
977
|
-
this._polarAngle = undefined;
|
|
1039
|
+
get firstSegment() {
|
|
1040
|
+
return this.segments[0];
|
|
978
1041
|
}
|
|
979
1042
|
|
|
980
|
-
get
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1043
|
+
get lastVertex() {
|
|
1044
|
+
return this.vertices[this.vertices.length - 1];
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
get lastSegment() {
|
|
1048
|
+
return this.segments[this.segments.length - 1];
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
_getD3CurveFunction(v){
|
|
1052
|
+
switch(v) {
|
|
1053
|
+
case CurveMode.Natural:
|
|
1054
|
+
return d3__namespace.curveNatural;
|
|
1055
|
+
case CurveMode.Basis:
|
|
1056
|
+
return d3__namespace.curveBasis;
|
|
1057
|
+
case CurveMode.BumpX:
|
|
1058
|
+
return d3__namespace.curveBumpX;
|
|
1059
|
+
case CurveMode.BumpY:
|
|
1060
|
+
return d3__namespace.curveBumpY;
|
|
1061
|
+
case CurveMode.Linear:
|
|
1062
|
+
return d3__namespace.curveLinear;
|
|
1063
|
+
case CurveMode.Step:
|
|
1064
|
+
return d3__namespace.curveStep;
|
|
1065
|
+
case CurveMode.CatmullRom:
|
|
1066
|
+
return d3__namespace.curveCatmullRom;
|
|
1067
|
+
case CurveMode.Cardinal:
|
|
1068
|
+
return d3__namespace.curveCardinal;
|
|
986
1069
|
default:
|
|
987
|
-
return
|
|
1070
|
+
return d3__namespace.curveLinear;
|
|
988
1071
|
}
|
|
989
1072
|
}
|
|
990
1073
|
|
|
991
|
-
get
|
|
992
|
-
return this.
|
|
1074
|
+
get vxShape(){
|
|
1075
|
+
return this._vxShape;
|
|
993
1076
|
}
|
|
994
1077
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
json.x = this.x;
|
|
1000
|
-
json.y = this.y;
|
|
1001
|
-
if (this.dataScope)
|
|
1002
|
-
json.dataScope = this.dataScope.toJSON();
|
|
1003
|
-
if (this._polarAngle !== undefined)
|
|
1004
|
-
json.polarAngle = this._polarAngle;
|
|
1005
|
-
json.shape = this.shape;
|
|
1006
|
-
json.width = this.width;
|
|
1007
|
-
json.height = this.height;
|
|
1008
|
-
json.radius = this.radius;
|
|
1009
|
-
json.fillColor = this.fillColor;
|
|
1010
|
-
json.opacity = this.opacity;
|
|
1011
|
-
json.strokeWidth = this.strokeWidth;
|
|
1012
|
-
json.strokeColor = this.strokeColor;
|
|
1013
|
-
return json;
|
|
1078
|
+
set vxShape(s){
|
|
1079
|
+
this._vxShape = s;
|
|
1080
|
+
for (let v of this.vertices)
|
|
1081
|
+
v.shape = s;
|
|
1014
1082
|
}
|
|
1015
1083
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
if (json.dataScope)
|
|
1019
|
-
v.dataScope = json.dataScope;
|
|
1020
|
-
if ("polarAngle" in json)
|
|
1021
|
-
v.polarAngle = json.polarAngle;
|
|
1022
|
-
v.shape = json.shape;
|
|
1023
|
-
v.width = json.width;
|
|
1024
|
-
v.height = json.height;
|
|
1025
|
-
v.radius = json.radius;
|
|
1026
|
-
v.fillColor = json.fillColor;
|
|
1027
|
-
v.opacity = json.opacity;
|
|
1028
|
-
v.strokeWidth = json.strokeWidth;
|
|
1029
|
-
v.strokeColor = json.strokeColor;
|
|
1030
|
-
return v;
|
|
1084
|
+
get vxWidth(){
|
|
1085
|
+
return this._vxWidth;
|
|
1031
1086
|
}
|
|
1032
1087
|
|
|
1033
|
-
|
|
1034
|
-
this.
|
|
1035
|
-
this.
|
|
1088
|
+
set vxWidth(s){
|
|
1089
|
+
this._vxWidth = s;
|
|
1090
|
+
for (let v of this.vertices)
|
|
1091
|
+
v.width = s;
|
|
1036
1092
|
}
|
|
1037
1093
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
if (this.dataScope) {
|
|
1041
|
-
v.dataScope = this.dataScope.clone();
|
|
1042
|
-
}
|
|
1043
|
-
v.shape = this.shape;
|
|
1044
|
-
v.width = this.width;
|
|
1045
|
-
v.height = this.height;
|
|
1046
|
-
v.radius = this.radius;
|
|
1047
|
-
v.fillColor = this.fillColor;
|
|
1048
|
-
v.opacity = this.opacity;
|
|
1049
|
-
v.strokeWidth = this.strokeWidth;
|
|
1050
|
-
v.strokeColor = this.strokeColor;
|
|
1051
|
-
return v;
|
|
1094
|
+
get vxHeight(){
|
|
1095
|
+
return this._vxHeight;
|
|
1052
1096
|
}
|
|
1053
1097
|
|
|
1054
|
-
set
|
|
1055
|
-
this.
|
|
1098
|
+
set vxHeight(s){
|
|
1099
|
+
this._vxHeight = s;
|
|
1100
|
+
for (let v of this.vertices)
|
|
1101
|
+
v.height = s;
|
|
1056
1102
|
}
|
|
1057
1103
|
|
|
1058
|
-
get
|
|
1059
|
-
return this.
|
|
1104
|
+
get vxRadius(){
|
|
1105
|
+
return this._vxRadius;
|
|
1060
1106
|
}
|
|
1061
|
-
}
|
|
1062
1107
|
|
|
1063
|
-
|
|
1108
|
+
set vxRadius(s){
|
|
1109
|
+
this._vxRadius = s;
|
|
1110
|
+
for (let v of this.vertices)
|
|
1111
|
+
v.radius = s;
|
|
1112
|
+
}
|
|
1064
1113
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
this.type = "segment";
|
|
1069
|
-
this._id = id;
|
|
1070
|
-
this.vertex1 = v1;
|
|
1071
|
-
this.vertex2 = v2;
|
|
1114
|
+
get vxFillColor(){
|
|
1115
|
+
return this._vxFillColor;
|
|
1116
|
+
}
|
|
1072
1117
|
|
|
1073
|
-
|
|
1074
|
-
this.
|
|
1118
|
+
set vxFillColor(s){
|
|
1119
|
+
this._vxFillColor = s;
|
|
1120
|
+
for (let v of this.vertices)
|
|
1121
|
+
v.fillColor = s;
|
|
1075
1122
|
}
|
|
1076
1123
|
|
|
1077
|
-
get
|
|
1078
|
-
return this.
|
|
1124
|
+
get vxStrokeColor(){
|
|
1125
|
+
return this._vxStrokeColor;
|
|
1079
1126
|
}
|
|
1080
1127
|
|
|
1081
|
-
|
|
1082
|
-
this.
|
|
1083
|
-
this.
|
|
1128
|
+
set vxStrokeColor(s){
|
|
1129
|
+
this._vxStrokeColor = s;
|
|
1130
|
+
for (let v of this.vertices)
|
|
1131
|
+
v.strokeColor = s;
|
|
1084
1132
|
}
|
|
1085
1133
|
|
|
1086
|
-
get
|
|
1087
|
-
return
|
|
1134
|
+
get vxStrokeWidth(){
|
|
1135
|
+
return this._vxStrokeWidth;
|
|
1088
1136
|
}
|
|
1089
1137
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1138
|
+
set vxStrokeWidth(s){
|
|
1139
|
+
this._vxStrokeWidth = s;
|
|
1140
|
+
for (let v of this.vertices)
|
|
1141
|
+
v.strokeWidth = s;
|
|
1092
1142
|
}
|
|
1093
|
-
}
|
|
1094
1143
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
super(args);
|
|
1099
|
-
this.type = "type" in args ? args.type : ItemType.Path;
|
|
1144
|
+
get vxOpacity(){
|
|
1145
|
+
return this._vxOpacity;
|
|
1146
|
+
}
|
|
1100
1147
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
this.styles["strokeDash"] = "none";
|
|
1148
|
+
set vxOpacity(s){
|
|
1149
|
+
this._vxOpacity = s;
|
|
1150
|
+
for (let v of this.vertices)
|
|
1151
|
+
v.opacity = s;
|
|
1152
|
+
}
|
|
1107
1153
|
|
|
1108
|
-
|
|
1109
|
-
this.vertexCounter = 0; //for assigning vertex ids
|
|
1110
|
-
this.segmentCounter = 0;
|
|
1111
|
-
this.segments = [];
|
|
1154
|
+
}
|
|
1112
1155
|
|
|
1113
|
-
|
|
1156
|
+
function evaluatePredicate(itm, p) {
|
|
1157
|
+
if ("field" in p) {
|
|
1158
|
+
if (!itm.dataScope) return false;
|
|
1159
|
+
let f = p["field"];
|
|
1160
|
+
if ("value" in p) {
|
|
1161
|
+
return itm.dataScope.getFieldValue(f) === p["value"];
|
|
1162
|
+
} else if ("interval" in p) {
|
|
1163
|
+
let v = itm.dataScope.getFieldValue(f);
|
|
1164
|
+
return v >= p["interval"][0] && v <= p["interval"][1];
|
|
1165
|
+
} else if ("values" in p) {
|
|
1166
|
+
return p["values"].indexOf(itm.dataScope.getFieldValue(f)) >= 0;
|
|
1167
|
+
} else {
|
|
1168
|
+
return itm.dataScope.hasField(f);
|
|
1169
|
+
}
|
|
1170
|
+
} else if ("channel" in p) {
|
|
1171
|
+
let c = p["channel"];
|
|
1172
|
+
if ("value" in p) {
|
|
1173
|
+
return itm[c] === p["value"];
|
|
1174
|
+
} else if ("interval" in p) {
|
|
1175
|
+
return itm[c] >= p["interval"][0] && itm[c] <= p["interval"][1];
|
|
1176
|
+
} else if ("values" in p) {
|
|
1177
|
+
return p["values"].indexOf(itm[c]) >= 0;
|
|
1178
|
+
}
|
|
1179
|
+
} else if ("type" in p) {
|
|
1180
|
+
return itm.type === p["type"];
|
|
1181
|
+
} else if ("id" in p) {
|
|
1182
|
+
return itm.id === p["id"];
|
|
1183
|
+
} else if ("classId" in p) {
|
|
1184
|
+
return itm.classId === p["classId"];
|
|
1185
|
+
} else if ("fields" in p) {
|
|
1186
|
+
if (!itm.dataScope) return false;
|
|
1187
|
+
let f1 = p["fields"][0], f2 = p["fields"][1],
|
|
1188
|
+
v1 = itm.dataScope.getFieldValue(f1), v2 = itm.dataScope.getFieldValue(f2);
|
|
1189
|
+
switch (p["operator"]) {
|
|
1190
|
+
case "==":
|
|
1191
|
+
return v1 == v2;
|
|
1192
|
+
case ">":
|
|
1193
|
+
return v1 > v2;
|
|
1194
|
+
case ">=":
|
|
1195
|
+
return v1 >= v2;
|
|
1196
|
+
case "<":
|
|
1197
|
+
return v1 < v2;
|
|
1198
|
+
case "<=":
|
|
1199
|
+
return v1 <= v2;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1114
1204
|
|
|
1115
|
-
|
|
1205
|
+
function findItems(container, predicates) {
|
|
1206
|
+
let result = [];
|
|
1207
|
+
_findItemsRecursive(container, predicates, result);
|
|
1208
|
+
return result;
|
|
1209
|
+
}
|
|
1116
1210
|
|
|
1117
|
-
|
|
1211
|
+
function _findItemsRecursive(itm, predicates, result) {
|
|
1212
|
+
if (!itm) return;
|
|
1213
|
+
if (itm.type == "axis" || itm.type == "legend" || itm.type == "gridlines") return;
|
|
1214
|
+
if (_matchCriteria(itm, predicates)) {
|
|
1215
|
+
result.push(itm);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
if (itm.vertices){
|
|
1219
|
+
for (let i of itm.vertices.concat(itm.segments)) {
|
|
1220
|
+
if (_matchCriteria(i, predicates))
|
|
1221
|
+
result.push(i);
|
|
1222
|
+
}
|
|
1223
|
+
} else if (itm.children && itm.children.length > 0) {
|
|
1224
|
+
for (let c of itm.children)
|
|
1225
|
+
_findItemsRecursive(c, predicates, result);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1118
1228
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1229
|
+
function _matchCriteria(cpnt, predicates) {
|
|
1230
|
+
for (let p of predicates) {
|
|
1231
|
+
if (!evaluatePredicate(cpnt, p))
|
|
1232
|
+
return false;
|
|
1233
|
+
}
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1121
1236
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1237
|
+
function getPeers(item, scene) {
|
|
1238
|
+
if (item.type == "vertex") {
|
|
1239
|
+
return _getPeerVertices(item, scene);
|
|
1240
|
+
} else if (item.type == "segment") {
|
|
1241
|
+
return _getPeerSegments(item, scene);
|
|
1242
|
+
} else {
|
|
1243
|
+
// return item.classId ? findItems(scene, d => d.classId == item.classId) : [];
|
|
1244
|
+
return item.classId ? findItems(scene, [{"classId": item.classId}]) : [];
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1130
1247
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1248
|
+
//returns an array of peer arrays, peers within each array have the same parent
|
|
1249
|
+
function getPeersGroupedByParent(item, scene) {
|
|
1250
|
+
let result = {}, peers = getPeers(item, scene);
|
|
1251
|
+
for (let p of peers) {
|
|
1252
|
+
let parent = p.parent.id;
|
|
1253
|
+
if (!(parent in result))
|
|
1254
|
+
result[parent] = [];
|
|
1255
|
+
result[parent].push(p);
|
|
1256
|
+
}
|
|
1257
|
+
return Object.keys(result).map(d => result[d]);
|
|
1258
|
+
}
|
|
1136
1259
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1260
|
+
function _getPeerSegments(segment, container) {
|
|
1261
|
+
if (segment.dataScope) {
|
|
1262
|
+
let parent = segment.parent;
|
|
1263
|
+
if (!parent) throw new Error("segment has no parent mark");
|
|
1264
|
+
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1265
|
+
let results = [];
|
|
1266
|
+
for (let p of parentPeers) {
|
|
1267
|
+
results = results.concat(p.segments);
|
|
1268
|
+
}
|
|
1269
|
+
return results;
|
|
1270
|
+
} else {
|
|
1271
|
+
let parent = segment.parent;
|
|
1272
|
+
if (!parent) throw new Error("segment has no parent mark");
|
|
1273
|
+
let index = parent.segments.indexOf(segment);
|
|
1274
|
+
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1275
|
+
let results = [];
|
|
1276
|
+
for (let p of parentPeers) {
|
|
1277
|
+
results.push(p.segments[index]);
|
|
1140
1278
|
}
|
|
1279
|
+
return results;
|
|
1141
1280
|
}
|
|
1281
|
+
}
|
|
1142
1282
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
case ItemType.Circle:
|
|
1155
|
-
json.args.x = this.x;
|
|
1156
|
-
json.args.y = this.y;
|
|
1157
|
-
json.args.radius = this.radius;
|
|
1158
|
-
break;
|
|
1159
|
-
case ItemType.Arc:
|
|
1160
|
-
case ItemType.Pie:
|
|
1161
|
-
json.args.x = this._x;
|
|
1162
|
-
json.args.y = this._y;
|
|
1163
|
-
json.args.innerRadius = this._innerRadius;
|
|
1164
|
-
json.args.outerRadius = this._outerRadius;
|
|
1165
|
-
json.args.startAngle = this._startAngle;
|
|
1166
|
-
json.args.endAngle = this._endAngle;
|
|
1167
|
-
break;
|
|
1168
|
-
default:
|
|
1169
|
-
json.vertices = [];
|
|
1170
|
-
for (let v of this.vertices)
|
|
1171
|
-
json.vertices.push(v.toJSON());
|
|
1172
|
-
if (this.type === ItemType.Polygon) {
|
|
1173
|
-
json.args.x = this._x;
|
|
1174
|
-
json.args.y = this._y;
|
|
1175
|
-
json.args.radius = this._radius;
|
|
1176
|
-
} else if (this.type === ItemType.Area) {
|
|
1177
|
-
json.args.baseline = this._baseline;
|
|
1178
|
-
json.args.orientation = this._orientation;
|
|
1179
|
-
}
|
|
1180
|
-
break;
|
|
1181
|
-
}
|
|
1182
|
-
// if (this.type === ItemType.Rect) {
|
|
1183
|
-
// json.args.width = this.width;
|
|
1184
|
-
// json.args.height = this.height;
|
|
1185
|
-
// json.args.top = this.top;
|
|
1186
|
-
// json.args.left = this.left;
|
|
1187
|
-
// } else if (this.type === ItemType.Circle) {
|
|
1188
|
-
// json.args.x = this.x;
|
|
1189
|
-
// json.args.y = this.y;
|
|
1190
|
-
// json.args.radius = this.radius;
|
|
1191
|
-
// } else if (this.type === ItemType.Arc) {
|
|
1192
|
-
// json.args.x = this._x;
|
|
1193
|
-
// json.args.y = this._y;
|
|
1194
|
-
// json.args.innerRadius = this._innerRadius;
|
|
1195
|
-
// json.args.outerRadius = this._outerRadius;
|
|
1196
|
-
// json.args.startAngle = this._startAngle;
|
|
1197
|
-
// json.args.endAngle = this._endAngle;
|
|
1198
|
-
// } else if (this.type === ItemType.Pie) {
|
|
1199
|
-
// json.args.x = this._x;
|
|
1200
|
-
// json.args.y = this._y;
|
|
1201
|
-
// json.args.radius = this.radius;
|
|
1202
|
-
// json.args.startAngle = this.startAngleDeg;
|
|
1203
|
-
// json.args.endAngle = this.endAngleDeg;
|
|
1204
|
-
// } else {
|
|
1205
|
-
// json.vertices = [];
|
|
1206
|
-
// for (let v of this.vertices)
|
|
1207
|
-
// json.vertices.push(v.toJSON());
|
|
1208
|
-
// if (this.type === ItemType.Polygon) {
|
|
1209
|
-
// json.args.x = this._x;
|
|
1210
|
-
// json.args.y = this._y;
|
|
1211
|
-
// json.args.radius = this._radius;
|
|
1212
|
-
// } else if (this.type === ItemType.Area) {
|
|
1213
|
-
// json.args.baseline = this._baseline;
|
|
1214
|
-
// json.args.orientation = this._orientation;
|
|
1215
|
-
// }
|
|
1216
|
-
// }
|
|
1217
|
-
json.vertexCounter = this.vertexCounter;
|
|
1218
|
-
json.segmentCounter = this.segmentCounter;
|
|
1219
|
-
//do not save segments, anchor and closed for now
|
|
1220
|
-
json.curveMode = this.curveMode;
|
|
1221
|
-
if (this._bounds)
|
|
1222
|
-
json.bounds = this._bounds.toJSON();
|
|
1223
|
-
json.boundsOffsets = this.boundsOffsets;
|
|
1224
|
-
for (let s of Vertex.styles) {
|
|
1225
|
-
json.args[s] = this[s];
|
|
1226
|
-
}
|
|
1227
|
-
return json;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
_setVertices(vertices) {
|
|
1231
|
-
let vertex, point;
|
|
1232
|
-
this.vertices = [];
|
|
1233
|
-
this.segments = [];
|
|
1234
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
1235
|
-
|
|
1236
|
-
if (i == vertices.length - 1 && vertices[i][0] === vertices[0][0] && vertices[i][1] === vertices[0][1] && this.type === ItemType.Path) {
|
|
1237
|
-
continue;
|
|
1283
|
+
function _getPeerVertices(vertex, container) {
|
|
1284
|
+
if (vertex.classId) ; else if (vertex.dataScope) {
|
|
1285
|
+
let parent = vertex.parent;
|
|
1286
|
+
if (!parent) throw new Error("vertex has no parent mark");
|
|
1287
|
+
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1288
|
+
let results = [];
|
|
1289
|
+
if (parent.type === ItemType.Area) {
|
|
1290
|
+
let idx = parent.vertices.indexOf(vertex), firstHalf = idx < parent.vertices.length/2;
|
|
1291
|
+
for (let p of parentPeers) {
|
|
1292
|
+
let vertices = firstHalf ? p.vertices.slice(0, p.vertices.length/2) : p.vertices.slice(p.vertices.length/2);
|
|
1293
|
+
results = results.concat(vertices.filter(d => d.dataScope));
|
|
1238
1294
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
vertex = new Vertex(point, this, this.vertexCounter++);
|
|
1243
|
-
|
|
1244
|
-
for (let vs of Vertex.styles){
|
|
1245
|
-
if (this[vs]){
|
|
1246
|
-
let temp = vs.replace("vx", "");
|
|
1247
|
-
vertex[temp[0].toLowerCase() + temp.slice(1)] = this[vs];
|
|
1248
|
-
}
|
|
1295
|
+
} else {
|
|
1296
|
+
for (let p of parentPeers) {
|
|
1297
|
+
results = results.concat(p.vertices.filter(d => d.dataScope));
|
|
1249
1298
|
}
|
|
1250
|
-
|
|
1251
|
-
this.vertices.push(vertex);
|
|
1252
|
-
if (i > 0)
|
|
1253
|
-
this.segments.push(new Segment(this.vertices[i-1], this.vertices[i], this, this.segmentCounter++));
|
|
1254
1299
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1300
|
+
return results;
|
|
1301
|
+
} else {
|
|
1302
|
+
let parent = vertex.parent;
|
|
1303
|
+
if (!parent) throw new Error("vertex has no parent mark");
|
|
1304
|
+
let index = parent.vertices.indexOf(vertex);
|
|
1305
|
+
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1306
|
+
let results = [];
|
|
1307
|
+
for (let p of parentPeers) {
|
|
1308
|
+
results.push(p.vertices[index]);
|
|
1262
1309
|
}
|
|
1310
|
+
return results;
|
|
1263
1311
|
}
|
|
1312
|
+
}
|
|
1264
1313
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1271
|
-
}
|
|
1272
|
-
if (this._dataScope)
|
|
1273
|
-
target._dataScope = this._dataScope.clone();
|
|
1274
|
-
target.closed = this.closed;
|
|
1275
|
-
target.curveMode = this.curveMode;
|
|
1276
|
-
target.vertices = [];
|
|
1277
|
-
target.segments = [];
|
|
1278
|
-
for (let v of this.vertices) {
|
|
1279
|
-
target.vertices.push(v._clone(target));
|
|
1280
|
-
}
|
|
1281
|
-
target.segmentCounter = 0;
|
|
1282
|
-
for (let i = 1; i < target.vertices.length; i++) {
|
|
1283
|
-
target.segments.push(new Segment(target.vertices[i-1], target.vertices[i], target, target.segmentCounter++));
|
|
1314
|
+
function getClosestLayout(item, type) {
|
|
1315
|
+
let parent = item.parent;
|
|
1316
|
+
while (parent && parent.type != ItemType.Scene) {
|
|
1317
|
+
if (parent.layout) {
|
|
1318
|
+
if ( (!type) || (type && parent.layout.type === type))
|
|
1319
|
+
return parent.layout;
|
|
1284
1320
|
}
|
|
1285
|
-
|
|
1286
|
-
target.segments.push(new Segment(target.vertices[target.vertices.length-1], target.vertices[0], target, target.segmentCounter++));
|
|
1321
|
+
parent = parent.parent;
|
|
1287
1322
|
}
|
|
1323
|
+
return undefined;
|
|
1324
|
+
}
|
|
1288
1325
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1326
|
+
function getCellBoundsInLayout(item) {
|
|
1327
|
+
let itm = item, parent = item.parent;
|
|
1328
|
+
while (parent && parent.type != ItemType.Scene) {
|
|
1329
|
+
if (parent.layout){
|
|
1330
|
+
let idx = parent.children.findIndex(d => d == itm);
|
|
1331
|
+
return parent.layout.cellBounds[idx];
|
|
1332
|
+
}
|
|
1333
|
+
itm = itm.parent;
|
|
1334
|
+
parent = itm.parent;
|
|
1296
1335
|
}
|
|
1336
|
+
return undefined;
|
|
1337
|
+
}
|
|
1297
1338
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
return new Rectangle(this._bounds.left - this.boundsOffsets.left, this._bounds.top - this.boundsOffsets.top, wd, ht);
|
|
1339
|
+
function getCellIndexInLayout(item) {
|
|
1340
|
+
let itm = item, parent = item.parent;
|
|
1341
|
+
while (parent && parent.type != ItemType.Scene) {
|
|
1342
|
+
if (parent.layout){
|
|
1343
|
+
return parent.children.findIndex(d => d == itm);
|
|
1344
|
+
}
|
|
1345
|
+
itm = itm.parent;
|
|
1346
|
+
parent = itm.parent;
|
|
1307
1347
|
}
|
|
1348
|
+
return undefined;
|
|
1349
|
+
}
|
|
1308
1350
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1351
|
+
function getCellBoundsInGridLayout(item) {
|
|
1352
|
+
let itm = item, parent = item.parent;
|
|
1353
|
+
while (parent && parent.type != ItemType.Scene) {
|
|
1354
|
+
if (parent.layout && parent.layout.type == LayoutType.Grid){
|
|
1355
|
+
let idx = parent.children.findIndex(d => d == itm);
|
|
1356
|
+
return parent.layout.cellBounds[idx];
|
|
1357
|
+
}
|
|
1358
|
+
itm = itm.parent;
|
|
1359
|
+
parent = itm.parent;
|
|
1311
1360
|
}
|
|
1361
|
+
return undefined;
|
|
1362
|
+
}
|
|
1312
1363
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1364
|
+
function getTopLevelLayout(item, type) {
|
|
1365
|
+
let parent = item.parent, layout = undefined;
|
|
1366
|
+
while (parent && parent.type !== ItemType.Scene) {
|
|
1367
|
+
if (parent.layout)
|
|
1368
|
+
if ( (!type) || (type && parent.layout.type === type))
|
|
1369
|
+
layout = parent.layout;
|
|
1370
|
+
parent = parent.parent;
|
|
1315
1371
|
}
|
|
1372
|
+
return layout;
|
|
1373
|
+
}
|
|
1316
1374
|
|
|
1317
|
-
|
|
1318
|
-
|
|
1375
|
+
function getEncodingKey(item) {
|
|
1376
|
+
if (item.classId) {
|
|
1377
|
+
return item.classId;
|
|
1378
|
+
} else if (item.type == "vertex" && item.dataScope) { //vertex created from densify
|
|
1379
|
+
if (item.parent.type === ItemType.Area) {
|
|
1380
|
+
let firstHalf = item.parent.vertices.indexOf(item) < item.parent.vertices.length/2;
|
|
1381
|
+
return item.parent.classId + "_v_" + (firstHalf ? 0 : item.parent.vertices.length-1) ;
|
|
1382
|
+
}
|
|
1383
|
+
else
|
|
1384
|
+
return item.parent.classId + "_v";
|
|
1385
|
+
} else if (item.type == "vertex") { //vertex with index
|
|
1386
|
+
return item.parent.classId + "_v_" + item.parent.vertices.indexOf(item);
|
|
1387
|
+
} else if (item.type == "segment" && item.dataScope) { //segment created from densify
|
|
1388
|
+
return item.parent.classId + "_s";
|
|
1389
|
+
} else if (item.type == "segment") { //segment with index
|
|
1390
|
+
return item.parent.classId + "_s_" + item.parent.segments.indexOf(item);
|
|
1391
|
+
} else {
|
|
1392
|
+
return null;
|
|
1319
1393
|
}
|
|
1394
|
+
}
|
|
1320
1395
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1396
|
+
function sameClass(item1, item2) {
|
|
1397
|
+
return getEncodingKey(item1).split("_")[0] === getEncodingKey(item2).split("_")[0];
|
|
1398
|
+
}
|
|
1324
1399
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1400
|
+
function getParents(items) {
|
|
1401
|
+
let result = [];
|
|
1402
|
+
for (let p of items) {
|
|
1403
|
+
if (p.parent && result.indexOf(p.parent) < 0)
|
|
1404
|
+
result.push(p.parent);
|
|
1327
1405
|
}
|
|
1406
|
+
return result;
|
|
1407
|
+
}
|
|
1328
1408
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1409
|
+
function getAllChildren(cpnt) {
|
|
1410
|
+
let result = [];
|
|
1411
|
+
if (cpnt.children && cpnt.children.length > 0) {
|
|
1412
|
+
for (let c of cpnt.children) {
|
|
1413
|
+
result.push(c);
|
|
1414
|
+
result = result.concat(getAllChildren(c));
|
|
1415
|
+
}
|
|
1331
1416
|
}
|
|
1417
|
+
return result;
|
|
1418
|
+
}
|
|
1332
1419
|
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1420
|
+
function getLeafMarks(cpnt) {
|
|
1421
|
+
let result = [];
|
|
1422
|
+
if (isMark(cpnt)) {
|
|
1423
|
+
result.push(cpnt);
|
|
1424
|
+
} else if (cpnt.children && cpnt.children.length > 0 && !isGuide(cpnt)) {
|
|
1425
|
+
for (let c of cpnt.children) {
|
|
1426
|
+
result = result.concat(getLeafMarks(c));
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return result;
|
|
1430
|
+
}
|
|
1336
1431
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1432
|
+
function getLeafItems(cpnt) {
|
|
1433
|
+
let result = [];
|
|
1434
|
+
if (cpnt.children && cpnt.children.length > 0) {
|
|
1435
|
+
for (let c of cpnt.children) {
|
|
1436
|
+
result = result.concat(getLeafItems(c));
|
|
1437
|
+
}
|
|
1438
|
+
} else {
|
|
1439
|
+
result.push(cpnt);
|
|
1339
1440
|
}
|
|
1441
|
+
return result;
|
|
1442
|
+
}
|
|
1340
1443
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1444
|
+
function isGuide(item) {
|
|
1445
|
+
return item.type === ItemType.Axis || item.type === ItemType.Legend || item.type === ItemType.Gridlines;
|
|
1446
|
+
}
|
|
1344
1447
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1448
|
+
function isMark(cmpnt) {
|
|
1449
|
+
return cmpnt instanceof Mark;
|
|
1450
|
+
}
|
|
1348
1451
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1452
|
+
function isPath(cmpnt) {
|
|
1453
|
+
return cmpnt instanceof Path;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
const ItemCounter = {
|
|
1457
|
+
"area" : 0,
|
|
1458
|
+
"rect" : 0,
|
|
1459
|
+
"circle": 0,
|
|
1460
|
+
"pie": 0,
|
|
1461
|
+
"line": 0,
|
|
1462
|
+
"path" : 0,
|
|
1463
|
+
"ring" : 0,
|
|
1464
|
+
"arc": 0,
|
|
1465
|
+
"image": 0,
|
|
1466
|
+
"pointText": 0,
|
|
1467
|
+
"collection": 0,
|
|
1468
|
+
"group": 0,
|
|
1469
|
+
"scene": 0,
|
|
1470
|
+
"axis": 0,
|
|
1471
|
+
"glyph": 0,
|
|
1472
|
+
"legend": 0,
|
|
1473
|
+
"polygon": 0,
|
|
1474
|
+
"gridlines": 0,
|
|
1475
|
+
"LinearGradient": 0,
|
|
1476
|
+
"link": 0,
|
|
1477
|
+
"scale": 0,
|
|
1478
|
+
"datatable": 0
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1481
|
+
function canAlign(items, direction, scene){
|
|
1482
|
+
if (direction == Alignment.Top || direction == Alignment.Bottom || direction == Alignment.Middle) {
|
|
1483
|
+
for (let item of items) {
|
|
1484
|
+
if (!canMoveVertically(item, scene))
|
|
1485
|
+
return false;
|
|
1352
1486
|
}
|
|
1353
|
-
|
|
1487
|
+
return true;
|
|
1354
1488
|
}
|
|
1355
1489
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
for (let v of this.vertices) {
|
|
1361
|
-
v.x = bounds.right - (wd/bWidth) * (bounds.right - v.x);
|
|
1362
|
-
}
|
|
1363
|
-
} else {
|
|
1364
|
-
for (let v of this.vertices) {
|
|
1365
|
-
v.x = bounds.left + (wd/bWidth) * (v.x - bounds.left);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
if (yRef === "top") {
|
|
1369
|
-
for (let v of this.vertices) {
|
|
1370
|
-
v.y = bounds.top + (ht/bHeight) * (v.y - bounds.top);
|
|
1371
|
-
}
|
|
1372
|
-
} else {
|
|
1373
|
-
for (let v of this.vertices) {
|
|
1374
|
-
v.y = bounds.bottom - (ht/bHeight) * (bounds.bottom - v.y);
|
|
1375
|
-
}
|
|
1490
|
+
if (direction == Alignment.Left || direction == Alignment.Right || direction == Alignment.Center) {
|
|
1491
|
+
for (let item of items) {
|
|
1492
|
+
if (!canMoveHorizontally(item, scene))
|
|
1493
|
+
return false;
|
|
1376
1494
|
}
|
|
1377
|
-
|
|
1495
|
+
return true;
|
|
1378
1496
|
}
|
|
1497
|
+
}
|
|
1379
1498
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
let
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
if (this.type === ItemType.Line || this.type === ItemType.Path) {
|
|
1388
|
-
let sw = this.styles["strokeWidth"] ? this.styles["strokeWidth"] : 1;
|
|
1389
|
-
if (left === right)
|
|
1390
|
-
this._bounds = new Rectangle(left - sw/2, top, right - left + sw, btm - top);
|
|
1391
|
-
else if (top === btm)
|
|
1392
|
-
this._bounds = new Rectangle(left, top - sw/2, right - left, btm - top + sw);
|
|
1499
|
+
function canMoveHorizontally(item, scene) {
|
|
1500
|
+
if (scene.getEncodingByItem(item, "x"))
|
|
1501
|
+
return false;
|
|
1502
|
+
if (item.parent && item.parent.layout) {
|
|
1503
|
+
let layout = item.parent.layout;
|
|
1504
|
+
if (layout.type == LayoutType.Grid && layout.numCols > 1) {
|
|
1505
|
+
return false;
|
|
1393
1506
|
}
|
|
1394
1507
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
let vertex = new Vertex(new Point(x, y), this, this.vertexCounter++);
|
|
1398
|
-
this.vertices.splice(i, 0, vertex);
|
|
1399
|
-
//TODO: handle segments
|
|
1508
|
+
if (item.parent && item.parent.type != ItemType.Scene){
|
|
1509
|
+
return canMoveHorizontally(item.parent, scene);
|
|
1400
1510
|
}
|
|
1511
|
+
return true;
|
|
1512
|
+
}
|
|
1401
1513
|
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
1514
|
+
function canMoveVertically(item, scene) {
|
|
1515
|
+
if (scene.getEncodingByItem(item, "y"))
|
|
1516
|
+
return false;
|
|
1517
|
+
if (item.parent && item.parent.layout) {
|
|
1518
|
+
let layout = item.parent.layout;
|
|
1519
|
+
if (layout.type == LayoutType.Grid && layout.numRows > 1) {
|
|
1520
|
+
return false;
|
|
1410
1521
|
}
|
|
1411
1522
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
let f;
|
|
1415
|
-
if (order)
|
|
1416
|
-
f = (a, b) => order.indexOf(a.dataScope.getFieldValue(field)) - order.indexOf(b.dataScope.getFieldValue(field));
|
|
1417
|
-
else
|
|
1418
|
-
f = (a, b) => (a.dataScope.getFieldValue(field) < b.dataScope.getFieldValue(field) ? -1 : 1 );
|
|
1419
|
-
this.vertices.sort(f);
|
|
1420
|
-
if (descending)
|
|
1421
|
-
this.vertices.reverse();
|
|
1422
|
-
for (let i = 0; i < this.segments.length; i++) {
|
|
1423
|
-
let segment = this.segments[i];
|
|
1424
|
-
segment.vertex1 = this.vertices[i];
|
|
1425
|
-
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
1426
|
-
}
|
|
1523
|
+
if (item.parent && item.parent.type != ItemType.Scene){
|
|
1524
|
+
return canMoveVertically(item.parent, scene);
|
|
1427
1525
|
}
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1428
1528
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
let curve = this._getD3CurveFunction(this.curveMode)(p);
|
|
1432
|
-
curve.lineStart();
|
|
1433
|
-
for (let vertex of this.vertices) {
|
|
1434
|
-
curve.point(vertex.x, vertex.y);
|
|
1435
|
-
}
|
|
1436
|
-
if (this.closed)
|
|
1437
|
-
curve.point(this.vertices[0].x, this.vertices[0].y);
|
|
1438
|
-
curve.lineEnd();
|
|
1439
|
-
|
|
1440
|
-
return p._;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// toSVG() {
|
|
1529
|
+
var CanvasProvider = {
|
|
1530
|
+
canvas : undefined,
|
|
1444
1531
|
|
|
1445
|
-
|
|
1532
|
+
getCanvas: function() {
|
|
1533
|
+
if (!window)
|
|
1534
|
+
return null;
|
|
1535
|
+
if (this.canvas === undefined) {
|
|
1536
|
+
this.canvas = document.createElement('canvas');
|
|
1537
|
+
}
|
|
1538
|
+
return this.canvas;
|
|
1539
|
+
},
|
|
1446
1540
|
|
|
1447
|
-
|
|
1541
|
+
getContext: function() {
|
|
1542
|
+
var canvas = this.getCanvas();
|
|
1543
|
+
return canvas ? canvas.getContext('2d') : null;
|
|
1544
|
+
},
|
|
1545
|
+
};
|
|
1448
1546
|
|
|
1449
|
-
|
|
1547
|
+
var SVGProvider = {
|
|
1548
|
+
svg: undefined,
|
|
1450
1549
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1550
|
+
getSVG: function() {
|
|
1551
|
+
if (!window)
|
|
1552
|
+
return null;
|
|
1553
|
+
if (this.svg === undefined) {
|
|
1554
|
+
this.svg = document.createElement('svg');
|
|
1555
|
+
}
|
|
1556
|
+
return this.svg;
|
|
1453
1557
|
}
|
|
1558
|
+
};
|
|
1454
1559
|
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1560
|
+
// export function getTextWidth(text, font) {
|
|
1561
|
+
// let context = CanvasProvider.getContext();
|
|
1562
|
+
// context.font = font;
|
|
1563
|
+
// let metrics = context.measureText(text);
|
|
1564
|
+
// return metrics.width;
|
|
1565
|
+
// }
|
|
1458
1566
|
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1567
|
+
function getTextSize(text, font, fontSize) {
|
|
1568
|
+
let context = CanvasProvider.getContext();
|
|
1569
|
+
context.font = font;
|
|
1570
|
+
let metrics = context.measureText(text);
|
|
1571
|
+
if (metrics.fontBoundingBoxAscent)
|
|
1572
|
+
return {width: metrics.width, height: metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent};
|
|
1573
|
+
else if (metrics.actualBoundingBoxAscent)
|
|
1574
|
+
return {width: metrics.width, height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent};
|
|
1575
|
+
else
|
|
1576
|
+
return {width: metrics.width, height: fontSize};
|
|
1577
|
+
}
|
|
1462
1578
|
|
|
1463
|
-
|
|
1464
|
-
|
|
1579
|
+
function getTopLevelGroup(item) {
|
|
1580
|
+
let parent = item.parent;
|
|
1581
|
+
if (parent.type == ItemType.Scene)
|
|
1582
|
+
return item;
|
|
1583
|
+
else
|
|
1584
|
+
return getTopLevelGroup(parent);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
function getTopLevelCollection(item) {
|
|
1588
|
+
let parent = item.parent;
|
|
1589
|
+
if (item.type == ItemType.Collection) {
|
|
1590
|
+
if (parent.type == ItemType.Collection) {
|
|
1591
|
+
return getTopLevelCollection(parent);
|
|
1592
|
+
} else
|
|
1593
|
+
return item;
|
|
1594
|
+
} else if (parent.type != ItemType.Scene) {
|
|
1595
|
+
return getTopLevelCollection(parent);
|
|
1596
|
+
} else {
|
|
1597
|
+
return undefined;
|
|
1465
1598
|
}
|
|
1599
|
+
}
|
|
1466
1600
|
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
return d3__namespace.curveBasis;
|
|
1473
|
-
case CurveMode.BumpX:
|
|
1474
|
-
return d3__namespace.curveBumpX;
|
|
1475
|
-
case CurveMode.BumpY:
|
|
1476
|
-
return d3__namespace.curveBumpY;
|
|
1477
|
-
case CurveMode.Linear:
|
|
1478
|
-
return d3__namespace.curveLinear;
|
|
1479
|
-
case CurveMode.Step:
|
|
1480
|
-
return d3__namespace.curveStep;
|
|
1481
|
-
case CurveMode.CatmullRom:
|
|
1482
|
-
return d3__namespace.curveCatmullRom;
|
|
1483
|
-
case CurveMode.Cardinal:
|
|
1484
|
-
return d3__namespace.curveCardinal;
|
|
1485
|
-
default:
|
|
1486
|
-
return d3__namespace.curveLinear;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
get vxShape(){
|
|
1491
|
-
return this._vxShape;
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
set vxShape(s){
|
|
1495
|
-
this._vxShape = s;
|
|
1496
|
-
for (let v of this.vertices)
|
|
1497
|
-
v.shape = s;
|
|
1498
|
-
}
|
|
1601
|
+
function polar2Cartesian(cx, cy, r, deg){
|
|
1602
|
+
let x = r * Math.cos(degree2radian(deg)),
|
|
1603
|
+
y = r * Math.sin(degree2radian(deg));
|
|
1604
|
+
return [x + cx, cy - y];
|
|
1605
|
+
}
|
|
1499
1606
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1607
|
+
function cartesian2Polar(x, y, cx, cy){
|
|
1608
|
+
let d = radian2degree(Math.atan2(cy - y, x - cx));
|
|
1609
|
+
d = Math.round( d * 10 + Number.EPSILON ) / 10;
|
|
1610
|
+
if (d < 0) d += 360;
|
|
1611
|
+
let r = Math.sqrt(Math.pow(x-cx, 2) + Math.pow(y-cy, 2));
|
|
1612
|
+
r = Math.round( r * 10 + Number.EPSILON ) / 10;
|
|
1613
|
+
return [d, r];
|
|
1614
|
+
}
|
|
1503
1615
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
v.width = s;
|
|
1508
|
-
}
|
|
1616
|
+
function degree2radian(d){
|
|
1617
|
+
return d * Math.PI/180;
|
|
1618
|
+
}
|
|
1509
1619
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1620
|
+
function radian2degree(r){
|
|
1621
|
+
return r * 180 / Math.PI;
|
|
1622
|
+
}
|
|
1513
1623
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1624
|
+
function CheckAreaOrien(area){
|
|
1625
|
+
let VNum = area.vertices.length;
|
|
1626
|
+
for (let i = 0; i < area.vertices.length / 2; i++) {
|
|
1627
|
+
let Vid1 = i, Vid2 = VNum - i - 1;
|
|
1628
|
+
let peer1 = area.vertices[Vid1], peer2 = area.vertices[Vid2];
|
|
1629
|
+
if (peer1.x == peer2.x && peer1.y == peer2.y) {
|
|
1630
|
+
continue;
|
|
1631
|
+
} else {
|
|
1632
|
+
if (peer1.x == peer2.x) {
|
|
1633
|
+
return "horizontal";
|
|
1634
|
+
} else {
|
|
1635
|
+
return "vertical";
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1518
1638
|
}
|
|
1639
|
+
}
|
|
1519
1640
|
|
|
1520
|
-
|
|
1521
|
-
return this._vxRadius;
|
|
1522
|
-
}
|
|
1641
|
+
class Layout {
|
|
1523
1642
|
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
v.radius = s;
|
|
1528
|
-
}
|
|
1643
|
+
constructor(args){
|
|
1644
|
+
this.group = undefined;
|
|
1645
|
+
}
|
|
1529
1646
|
|
|
1530
|
-
|
|
1531
|
-
return this._vxFillColor;
|
|
1532
|
-
}
|
|
1647
|
+
run(){}
|
|
1533
1648
|
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
for (let v of this.vertices)
|
|
1537
|
-
v.fillColor = s;
|
|
1538
|
-
}
|
|
1649
|
+
clone(){}
|
|
1650
|
+
}
|
|
1539
1651
|
|
|
1540
|
-
|
|
1541
|
-
return this._vxStrokeColor;
|
|
1542
|
-
}
|
|
1652
|
+
class GridLayout extends Layout {
|
|
1543
1653
|
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1654
|
+
constructor(args) {
|
|
1655
|
+
super();
|
|
1656
|
+
this.type = "grid";
|
|
1657
|
+
this._numCols = args["numCols"];
|
|
1658
|
+
this._numRows = args["numRows"];
|
|
1659
|
+
this._dir = ("dir" in args) ? args["dir"] : [GridLayout.direction.Left2Right, GridLayout.direction.Top2Bottom];
|
|
1660
|
+
// this._hDir = ("hDir" in args) ? args["hDir"] : GridLayout.direction.Left2Right;
|
|
1661
|
+
// this._vDir = ("vDir" in args) ? args["vDir"] : GridLayout.direction.Top2Bottom;
|
|
1662
|
+
this._rowGap = "rowGap" in args && args["rowGap"] !== undefined ? args["rowGap"] : 5;
|
|
1663
|
+
this._colGap = "colGap" in args && args["colGap"] !== undefined ? args["colGap"] : 5;
|
|
1664
|
+
this._cellHorzAlignment = "horzCellAlignment" in args && this._validateCellAlignment("h", args["horzCellAlignment"]) ? args["horzCellAlignment"] : Alignment.Left;
|
|
1665
|
+
this._cellVertAlignment = "vertCellAlignment" in args && this._validateCellAlignment("v", args["vertCellAlignment"]) ? args["vertCellAlignment"] : Alignment.Bottom;
|
|
1666
|
+
if (!this._numCols && !this._numRows)
|
|
1667
|
+
this._numRows = 1;
|
|
1548
1668
|
}
|
|
1549
1669
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1670
|
+
_validateCellAlignment(orientation, v) {
|
|
1671
|
+
if (orientation === "h" && [Alignment.Left, Alignment.Center, Alignment.Right].indexOf(v) >= 0){
|
|
1672
|
+
return true;
|
|
1673
|
+
} else if (orientation === "v" && [Alignment.Top, Alignment.Middle, Alignment.Bottom].indexOf(v) >= 0){
|
|
1674
|
+
return true;
|
|
1675
|
+
}
|
|
1676
|
+
console.warn("Invalid alignment:", v);
|
|
1677
|
+
return false;
|
|
1553
1678
|
|
|
1554
|
-
set vxStrokeWidth(s){
|
|
1555
|
-
this._vxStrokeWidth = s;
|
|
1556
|
-
for (let v of this.vertices)
|
|
1557
|
-
v.strokeWidth = s;
|
|
1558
1679
|
}
|
|
1559
1680
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1681
|
+
toJSON() {
|
|
1682
|
+
let json = {args: {}};
|
|
1683
|
+
json.type = this.type;
|
|
1684
|
+
json.args.numCols = this._numCols;
|
|
1685
|
+
json.args.numRows = this._numRows;
|
|
1686
|
+
json.args.colGap = this._colGap;
|
|
1687
|
+
json.args.rowGap = this._rowGap;
|
|
1688
|
+
json.args.horzCellAlignment = this._cellHorzAlignment;
|
|
1689
|
+
json.args.vertCellAlignment = this._cellVertAlignment;
|
|
1690
|
+
json.left = this._left;
|
|
1691
|
+
json.top = this._top;
|
|
1692
|
+
json.args.dir = this._dir;
|
|
1693
|
+
return json;
|
|
1562
1694
|
}
|
|
1563
1695
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1696
|
+
clone() {
|
|
1697
|
+
return new GridLayout({
|
|
1698
|
+
numCols: this._numCols,
|
|
1699
|
+
numRows: this._numRows,
|
|
1700
|
+
// hDir: this._hDir,
|
|
1701
|
+
// vDir: this._vDir,
|
|
1702
|
+
dir: this._dir,
|
|
1703
|
+
colGap: this._colGap,
|
|
1704
|
+
rowGap: this._rowGap
|
|
1705
|
+
});
|
|
1568
1706
|
}
|
|
1569
1707
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
} else if ("interval" in p) {
|
|
1579
|
-
let v = itm.dataScope.getFieldValue(f);
|
|
1580
|
-
return v >= p["interval"][0] && v <= p["interval"][1];
|
|
1581
|
-
} else if ("values" in p) {
|
|
1582
|
-
return p["values"].indexOf(itm.dataScope.getFieldValue(f)) >= 0;
|
|
1583
|
-
} else {
|
|
1584
|
-
return itm.dataScope.hasField(f);
|
|
1585
|
-
}
|
|
1586
|
-
} else if ("channel" in p) {
|
|
1587
|
-
let c = p["channel"];
|
|
1588
|
-
if ("value" in p) {
|
|
1589
|
-
return itm[c] === p["value"];
|
|
1590
|
-
} else if ("interval" in p) {
|
|
1591
|
-
return itm[c] >= p["interval"][0] && itm[c] <= p["interval"][1];
|
|
1592
|
-
} else if ("values" in p) {
|
|
1593
|
-
return p["values"].indexOf(itm[c]) >= 0;
|
|
1594
|
-
}
|
|
1595
|
-
} else if ("type" in p) {
|
|
1596
|
-
return itm.type === p["type"];
|
|
1597
|
-
} else if ("id" in p) {
|
|
1598
|
-
return itm.id === p["id"];
|
|
1599
|
-
} else if ("classId" in p) {
|
|
1600
|
-
return itm.classId === p["classId"];
|
|
1601
|
-
} else if ("fields" in p) {
|
|
1602
|
-
if (!itm.dataScope) return false;
|
|
1603
|
-
let f1 = p["fields"][0], f2 = p["fields"][1],
|
|
1604
|
-
v1 = itm.dataScope.getFieldValue(f1), v2 = itm.dataScope.getFieldValue(f2);
|
|
1605
|
-
switch (p["operator"]) {
|
|
1606
|
-
case "==":
|
|
1607
|
-
return v1 == v2;
|
|
1608
|
-
case ">":
|
|
1609
|
-
return v1 > v2;
|
|
1610
|
-
case ">=":
|
|
1611
|
-
return v1 >= v2;
|
|
1612
|
-
case "<":
|
|
1613
|
-
return v1 < v2;
|
|
1614
|
-
case "<=":
|
|
1615
|
-
return v1 <= v2;
|
|
1708
|
+
get cellBounds() {
|
|
1709
|
+
let numCols, numRows, group = this.group, colGap = this._colGap, rowGap = this._rowGap;
|
|
1710
|
+
if (this._numRows) {
|
|
1711
|
+
numRows = this._numRows;
|
|
1712
|
+
numCols = Math.ceil(this.group.children.length/this._numRows);
|
|
1713
|
+
} else if (this._numCols) {
|
|
1714
|
+
numCols = this._numCols;
|
|
1715
|
+
numRows = Math.ceil(this.group.children.length/this._numCols);
|
|
1616
1716
|
}
|
|
1617
|
-
}
|
|
1618
|
-
return false;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
function findItems(container, predicates) {
|
|
1622
|
-
let result = [];
|
|
1623
|
-
_findItemsRecursive(container, predicates, result);
|
|
1624
|
-
return result;
|
|
1625
|
-
}
|
|
1626
1717
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
if (itm.vertices){
|
|
1635
|
-
for (let i of itm.vertices.concat(itm.segments)) {
|
|
1636
|
-
if (_matchCriteria(i, predicates))
|
|
1637
|
-
result.push(i);
|
|
1718
|
+
let bounds = group.children.map(d => d.bounds);
|
|
1719
|
+
if (this._left === undefined) {
|
|
1720
|
+
let lefts = bounds.map(d => d.left),
|
|
1721
|
+
tops = bounds.map(d => d.top);
|
|
1722
|
+
this._left = Math.min(...lefts);
|
|
1723
|
+
this._top = Math.min(...tops);
|
|
1638
1724
|
}
|
|
1639
|
-
} else if (itm.children && itm.children.length > 0) {
|
|
1640
|
-
for (let c of itm.children)
|
|
1641
|
-
_findItemsRecursive(c, predicates, result);
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
1725
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
//returns an array of peer arrays, peers within each array have the same parent
|
|
1665
|
-
function getPeersGroupedByParent(item, scene) {
|
|
1666
|
-
let result = {}, peers = getPeers(item, scene);
|
|
1667
|
-
for (let p of peers) {
|
|
1668
|
-
let parent = p.parent.id;
|
|
1669
|
-
if (!(parent in result))
|
|
1670
|
-
result[parent] = [];
|
|
1671
|
-
result[parent].push(p);
|
|
1672
|
-
}
|
|
1673
|
-
return Object.keys(result).map(d => result[d]);
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
function _getPeerSegments(segment, container) {
|
|
1677
|
-
if (segment.dataScope) {
|
|
1678
|
-
let parent = segment.parent;
|
|
1679
|
-
if (!parent) throw new Error("segment has no parent mark");
|
|
1680
|
-
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1681
|
-
let results = [];
|
|
1682
|
-
for (let p of parentPeers) {
|
|
1683
|
-
results = results.concat(p.segments);
|
|
1684
|
-
}
|
|
1685
|
-
return results;
|
|
1686
|
-
} else {
|
|
1687
|
-
let parent = segment.parent;
|
|
1688
|
-
if (!parent) throw new Error("segment has no parent mark");
|
|
1689
|
-
let index = parent.segments.indexOf(segment);
|
|
1690
|
-
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1691
|
-
let results = [];
|
|
1692
|
-
for (let p of parentPeers) {
|
|
1693
|
-
results.push(p.segments[index]);
|
|
1694
|
-
}
|
|
1695
|
-
return results;
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
function _getPeerVertices(vertex, container) {
|
|
1700
|
-
if (vertex.classId) ; else if (vertex.dataScope) {
|
|
1701
|
-
let parent = vertex.parent;
|
|
1702
|
-
if (!parent) throw new Error("vertex has no parent mark");
|
|
1703
|
-
let parentPeers = findItems(container, [{"classId": parent.classId}]);
|
|
1704
|
-
let results = [];
|
|
1705
|
-
if (parent.type === ItemType.Area) {
|
|
1706
|
-
let idx = parent.vertices.indexOf(vertex), firstHalf = idx < parent.vertices.length/2;
|
|
1707
|
-
for (let p of parentPeers) {
|
|
1708
|
-
let vertices = firstHalf ? p.vertices.slice(0, p.vertices.length/2) : p.vertices.slice(p.vertices.length/2);
|
|
1709
|
-
results = results.concat(vertices.filter(d => d.dataScope));
|
|
1710
|
-
}
|
|
1711
|
-
} else {
|
|
1712
|
-
for (let p of parentPeers) {
|
|
1713
|
-
results = results.concat(p.vertices.filter(d => d.dataScope));
|
|
1726
|
+
let wds = bounds.map(d => d.width),
|
|
1727
|
+
hts = bounds.map(d => d.height),
|
|
1728
|
+
cellWidth = Math.max(...wds),
|
|
1729
|
+
cellHeight = Math.max(...hts);
|
|
1730
|
+
|
|
1731
|
+
//cell size should be determined by the scale range extent if bound to data
|
|
1732
|
+
let leftOffset = 0; //, topOffset = 0;
|
|
1733
|
+
|
|
1734
|
+
let xEncs = group.getInternalEncodings("x"),
|
|
1735
|
+
yEncs = group.getInternalEncodings("y"),
|
|
1736
|
+
wdEncs = group.getInternalEncodings("width"),
|
|
1737
|
+
htEncs = group.getInternalEncodings("height");
|
|
1738
|
+
if (xEncs.length > 0) {
|
|
1739
|
+
let xEnc = xEncs[xEncs.length -1];
|
|
1740
|
+
cellWidth = xEnc.scale.rangeExtent;
|
|
1741
|
+
leftOffset = xEnc.scale.range[0];
|
|
1742
|
+
if (xEnc.scale.type === "point") {
|
|
1743
|
+
//TODO: need to handle variable sizes
|
|
1744
|
+
cellWidth += xEnc.anyItem.bounds.width;
|
|
1714
1745
|
}
|
|
1746
|
+
} else if (wdEncs.length > 0 && wdEncs[wdEncs.length -1]._rectNegativeValues) { //width encoding with negative values
|
|
1747
|
+
cellWidth = wdEncs[wdEncs.length -1].scale.rangeExtent;
|
|
1748
|
+
leftOffset = wdEncs[wdEncs.length -1].scale.range[0];
|
|
1715
1749
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
}
|
|
1726
|
-
return results;
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
function getClosestLayout(item, type) {
|
|
1731
|
-
let parent = item.parent;
|
|
1732
|
-
while (parent && parent.type != ItemType.Scene) {
|
|
1733
|
-
if (parent.layout) {
|
|
1734
|
-
if ( (!type) || (type && parent.layout.type === type))
|
|
1735
|
-
return parent.layout;
|
|
1736
|
-
}
|
|
1737
|
-
parent = parent.parent;
|
|
1738
|
-
}
|
|
1739
|
-
return undefined;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
function getCellBoundsInLayout(item) {
|
|
1743
|
-
let itm = item, parent = item.parent;
|
|
1744
|
-
while (parent && parent.type != ItemType.Scene) {
|
|
1745
|
-
if (parent.layout){
|
|
1746
|
-
let idx = parent.children.findIndex(d => d == itm);
|
|
1747
|
-
return parent.layout.cellBounds[idx];
|
|
1748
|
-
}
|
|
1749
|
-
itm = itm.parent;
|
|
1750
|
-
parent = itm.parent;
|
|
1751
|
-
}
|
|
1752
|
-
return undefined;
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
function getCellIndexInLayout(item) {
|
|
1756
|
-
let itm = item, parent = item.parent;
|
|
1757
|
-
while (parent && parent.type != ItemType.Scene) {
|
|
1758
|
-
if (parent.layout){
|
|
1759
|
-
return parent.children.findIndex(d => d == itm);
|
|
1760
|
-
}
|
|
1761
|
-
itm = itm.parent;
|
|
1762
|
-
parent = itm.parent;
|
|
1763
|
-
}
|
|
1764
|
-
return undefined;
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
function getCellBoundsInGridLayout(item) {
|
|
1768
|
-
let itm = item, parent = item.parent;
|
|
1769
|
-
while (parent && parent.type != ItemType.Scene) {
|
|
1770
|
-
if (parent.layout && parent.layout.type == LayoutType.Grid){
|
|
1771
|
-
let idx = parent.children.findIndex(d => d == itm);
|
|
1772
|
-
return parent.layout.cellBounds[idx];
|
|
1750
|
+
if (yEncs.length > 0) {
|
|
1751
|
+
let yEnc = yEncs[yEncs.length -1];
|
|
1752
|
+
cellHeight = yEnc.scale.rangeExtent;
|
|
1753
|
+
if (yEnc.scale.type === "point") {
|
|
1754
|
+
//TODO: need to handle variable sizes
|
|
1755
|
+
cellHeight += yEnc.anyItem.bounds.height;
|
|
1756
|
+
}
|
|
1757
|
+
} else if (htEncs.length > 0 && htEncs[htEncs.length -1]._rectNegativeValues) { //width encoding with negative values
|
|
1758
|
+
cellHeight = htEncs[htEncs.length -1].scale.rangeExtent;
|
|
1773
1759
|
}
|
|
1774
|
-
itm = itm.parent;
|
|
1775
|
-
parent = itm.parent;
|
|
1776
|
-
}
|
|
1777
|
-
return undefined;
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
function getTopLevelLayout(item, type) {
|
|
1781
|
-
let parent = item.parent, layout = undefined;
|
|
1782
|
-
while (parent && parent.type !== ItemType.Scene) {
|
|
1783
|
-
if (parent.layout)
|
|
1784
|
-
if ( (!type) || (type && parent.layout.type === type))
|
|
1785
|
-
layout = parent.layout;
|
|
1786
|
-
parent = parent.parent;
|
|
1787
|
-
}
|
|
1788
|
-
return layout;
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
function getEncodingKey(item) {
|
|
1792
|
-
if (item.classId) {
|
|
1793
|
-
return item.classId;
|
|
1794
|
-
} else if (item.type == "vertex" && item.dataScope) { //vertex created from densify
|
|
1795
|
-
if (item.parent.type === ItemType.Area) {
|
|
1796
|
-
let firstHalf = item.parent.vertices.indexOf(item) < item.parent.vertices.length/2;
|
|
1797
|
-
return item.parent.classId + "_v_" + (firstHalf ? 0 : item.parent.vertices.length-1) ;
|
|
1798
|
-
}
|
|
1799
|
-
else
|
|
1800
|
-
return item.parent.classId + "_v";
|
|
1801
|
-
} else if (item.type == "vertex") { //vertex with index
|
|
1802
|
-
return item.parent.classId + "_v_" + item.parent.vertices.indexOf(item);
|
|
1803
|
-
} else if (item.type == "segment" && item.dataScope) { //segment created from densify
|
|
1804
|
-
return item.parent.classId + "_s";
|
|
1805
|
-
} else if (item.type == "segment") { //segment with index
|
|
1806
|
-
return item.parent.classId + "_s_" + item.parent.segments.indexOf(item);
|
|
1807
|
-
} else {
|
|
1808
|
-
return null;
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
function sameClass(item1, item2) {
|
|
1813
|
-
return getEncodingKey(item1).split("_")[0] === getEncodingKey(item2).split("_")[0];
|
|
1814
|
-
}
|
|
1815
1760
|
|
|
1816
|
-
|
|
1817
|
-
let result = [];
|
|
1818
|
-
for (let p of items) {
|
|
1819
|
-
if (p.parent && result.indexOf(p.parent) < 0)
|
|
1820
|
-
result.push(p.parent);
|
|
1821
|
-
}
|
|
1822
|
-
return result;
|
|
1823
|
-
}
|
|
1761
|
+
let cb = [], cellCount = numRows * numCols;
|
|
1824
1762
|
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1763
|
+
switch (this._dir[0]) {
|
|
1764
|
+
case GridLayout.direction.Left2Right:
|
|
1765
|
+
switch (this._dir[1]) {
|
|
1766
|
+
case GridLayout.direction.Top2Bottom:
|
|
1767
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1768
|
+
cb.push(new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
1769
|
+
this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
1770
|
+
}
|
|
1771
|
+
break;
|
|
1772
|
+
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
1773
|
+
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
1774
|
+
case GridLayout.direction.Bottom2Top:
|
|
1775
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1776
|
+
cb.push(new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
1777
|
+
this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
1778
|
+
}
|
|
1779
|
+
break;
|
|
1780
|
+
// return group.children.map((d, i) => new Rectangle(this._left + (cellWidth + colGap) * (i%numCols) + leftOffset,
|
|
1781
|
+
// this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
1782
|
+
}
|
|
1783
|
+
break;
|
|
1784
|
+
case GridLayout.direction.Right2Left:
|
|
1785
|
+
switch (this._dir[1]) {
|
|
1786
|
+
case GridLayout.direction.Top2Bottom:
|
|
1787
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1788
|
+
cb.push(new Rectangle(leftOffset + this._left + (numCols - 1) * (cellWidth + colGap) - (cellWidth + colGap) * (i%numCols),
|
|
1789
|
+
this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
1790
|
+
}
|
|
1791
|
+
break;
|
|
1792
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1) * (cellWidth + colGap) - (cellWidth + colGap) * (i%numCols),
|
|
1793
|
+
// this._top + (cellHeight + rowGap) * Math.floor(i/numCols), cellWidth, cellHeight));
|
|
1794
|
+
case GridLayout.direction.Bottom2Top: {
|
|
1795
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1796
|
+
cb.push(new Rectangle(leftOffset + this._left + (numCols - 1 - i%numCols) * (cellWidth + colGap),
|
|
1797
|
+
this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
1798
|
+
}
|
|
1799
|
+
break;
|
|
1800
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (numCols - 1 - i%numCols) * (cellWidth + colGap),
|
|
1801
|
+
// this._top + (this.numRows - 1 - Math.floor(i/numCols)) * (cellHeight + rowGap), cellWidth, cellHeight));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
break;
|
|
1805
|
+
case GridLayout.direction.Top2Bottom:
|
|
1806
|
+
switch (this._dir[1]) {
|
|
1807
|
+
case GridLayout.direction.Left2Right:
|
|
1808
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1809
|
+
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1810
|
+
this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1811
|
+
}
|
|
1812
|
+
break;
|
|
1813
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1814
|
+
// this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1815
|
+
case GridLayout.direction.Right2Left:
|
|
1816
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1817
|
+
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1818
|
+
this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1819
|
+
}
|
|
1820
|
+
break;
|
|
1821
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1822
|
+
// this._top + (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1823
|
+
}
|
|
1824
|
+
break;
|
|
1825
|
+
case GridLayout.direction.Bottom2Top:
|
|
1826
|
+
switch (this._dir[1]) {
|
|
1827
|
+
case GridLayout.direction.Left2Right:
|
|
1828
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1829
|
+
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1830
|
+
this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1831
|
+
}
|
|
1832
|
+
break;
|
|
1833
|
+
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight)));
|
|
1834
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1835
|
+
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1836
|
+
case GridLayout.direction.Right2Left:
|
|
1837
|
+
for (let i = 0; i < cellCount; i++) {
|
|
1838
|
+
cb.push(new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1839
|
+
this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1840
|
+
}
|
|
1841
|
+
break;
|
|
1842
|
+
// return group.children.map((d, i) => new Rectangle(leftOffset + this._left + (cellWidth + colGap) * (this.numCols - 1) - (cellWidth + colGap) * Math.floor(i/this.numRows),
|
|
1843
|
+
// this._top + (cellHeight + rowGap) * (this.numRows - 1) - (cellHeight + rowGap) * (i%this.numRows), cellWidth, cellHeight));
|
|
1844
|
+
}
|
|
1845
|
+
break;
|
|
1831
1846
|
}
|
|
1832
|
-
}
|
|
1833
|
-
return result;
|
|
1834
|
-
}
|
|
1835
1847
|
|
|
1836
|
-
|
|
1837
|
-
let result = [];
|
|
1838
|
-
if (isMark(cpnt)) {
|
|
1839
|
-
result.push(cpnt);
|
|
1840
|
-
} else if (cpnt.children && cpnt.children.length > 0 && !isGuide(cpnt)) {
|
|
1841
|
-
for (let c of cpnt.children) {
|
|
1842
|
-
result = result.concat(getLeafMarks(c));
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
return result;
|
|
1846
|
-
}
|
|
1848
|
+
return cb;
|
|
1847
1849
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1850
|
+
// if (group.firstChild.type === ItemType.Glyph) {
|
|
1851
|
+
// let items = group.firstChild.children, xRanges = [], yRanges = [], minLefts = [], minTops = [], scn = group.getScene();
|
|
1852
|
+
// for (let itm of items) {
|
|
1853
|
+
// let xEnc = scn.positionBound(itm, "x"), wdEnc = scn.sizeBound(itm, "width"),
|
|
1854
|
+
// yEnc = scn.positionBound(itm, "y"), htEnc = scn.sizeBound(itm, "height"),
|
|
1855
|
+
// peers = getPeers(itm, scn);
|
|
1856
|
+
// xRanges.push(xEnc? xEnc.scale.rangeExtent : wdEnc && wdEnc._rectNegativeValues ? wdEnc.scale.rangeExtent : undefined);
|
|
1857
|
+
// yRanges.push(yEnc? yEnc.scale.rangeExtent : htEnc && htEnc._rectNegativeValues ? htEnc.scale.rangeExtent : undefined);
|
|
1858
|
+
// minLefts.push(Math.min(...peers.map(d => d.bounds.left)));
|
|
1859
|
+
// minTops.push(Math.min(...peers.map(d => d.bounds.top)));
|
|
1860
|
+
// }
|
|
1861
|
+
// let wds = [], hts = [];
|
|
1862
|
+
// for (let c of group.children) {
|
|
1863
|
+
// let xCoords = [], yCoords = [];
|
|
1864
|
+
// for (const [i, m] of c.children.entries()) {
|
|
1865
|
+
// xCoords.push( m.refBounds.left, m.refBounds.left + (xRanges[i] ? xRanges[i] : m.bounds.width));
|
|
1866
|
+
// yCoords.push( m.refBounds.top, m.refBounds.top + (yRanges[i] ? yRanges[i] : m.bounds.height));
|
|
1867
|
+
// }
|
|
1868
|
+
// wds.push(Math.max(...xCoords) - Math.min(...xCoords));
|
|
1869
|
+
// hts.push(Math.max(...yCoords) - Math.min(...yCoords));
|
|
1870
|
+
// }
|
|
1871
|
+
// cellWidth = Math.max(...wds);
|
|
1872
|
+
// cellHeight = Math.max(...hts);
|
|
1873
|
+
// } else
|
|
1874
|
+
// if (group.firstChild.type === ItemType.Collection && group.firstChild.layout && group.firstChild.layout.type === LayoutType.Grid) {
|
|
1875
|
+
// let cb = group.firstChild.layout.cellBounds[0];
|
|
1876
|
+
// cellWidth = (cb.width + group.firstChild.layout.colGap) * Math.max(...group.children.map(d => d.layout.numCols)) - group.firstChild.layout.colGap;
|
|
1877
|
+
// cellHeight = (cb.height + group.firstChild.layout.rowGap) * Math.max(...group.children.map(d => d.layout.numRows)) - group.firstChild.layout.rowGap;
|
|
1878
|
+
// } else {
|
|
1856
1879
|
}
|
|
1857
|
-
return result;
|
|
1858
|
-
}
|
|
1859
1880
|
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1881
|
+
run() {
|
|
1882
|
+
if (this.group == undefined|| !this.group.children || this.group.children.length === 0)
|
|
1883
|
+
return;
|
|
1863
1884
|
|
|
1864
|
-
|
|
1865
|
-
return cmpnt instanceof Mark;
|
|
1866
|
-
}
|
|
1885
|
+
let cellBounds = this.cellBounds;
|
|
1867
1886
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1887
|
+
let xEncs = this.group.getInternalEncodings("x"),
|
|
1888
|
+
yEncs = this.group.getInternalEncodings("y"),
|
|
1889
|
+
wdEncs = this.group.getInternalEncodings("width"),
|
|
1890
|
+
htEncs = this.group.getInternalEncodings("height");
|
|
1891
|
+
for (let i = 0; i < this.group.children.length; i++) {
|
|
1892
|
+
let c = this.group.children[i];
|
|
1893
|
+
let gridBound = cellBounds[i];
|
|
1871
1894
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
"circle": 0,
|
|
1876
|
-
"pie": 0,
|
|
1877
|
-
"line": 0,
|
|
1878
|
-
"path" : 0,
|
|
1879
|
-
"ring" : 0,
|
|
1880
|
-
"arc": 0,
|
|
1881
|
-
"image": 0,
|
|
1882
|
-
"pointText": 0,
|
|
1883
|
-
"collection": 0,
|
|
1884
|
-
"group": 0,
|
|
1885
|
-
"scene": 0,
|
|
1886
|
-
"axis": 0,
|
|
1887
|
-
"glyph": 0,
|
|
1888
|
-
"legend": 0,
|
|
1889
|
-
"polygon": 0,
|
|
1890
|
-
"gridlines": 0,
|
|
1891
|
-
"LinearGradient": 0,
|
|
1892
|
-
"link": 0,
|
|
1893
|
-
"scale": 0,
|
|
1894
|
-
"datatable": 0
|
|
1895
|
-
};
|
|
1895
|
+
let dx = gridBound.x - c.bounds.x,
|
|
1896
|
+
dy = gridBound.y - c.bounds.y;
|
|
1897
|
+
c._doTranslate(dx, dy);
|
|
1896
1898
|
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1899
|
+
//alignment in cell if c's position is not bound to data
|
|
1900
|
+
let cdx = 0, cdy = 0;
|
|
1901
|
+
if (xEncs.length == 0) {
|
|
1902
|
+
switch(this._cellHorzAlignment) {
|
|
1903
|
+
case Alignment.Left:
|
|
1904
|
+
cdx = gridBound.left - c.bounds.left;
|
|
1905
|
+
break;
|
|
1906
|
+
case Alignment.Center:
|
|
1907
|
+
cdx = gridBound.x - c.bounds.x;
|
|
1908
|
+
break;
|
|
1909
|
+
case Alignment.Right:
|
|
1910
|
+
cdx = gridBound.right - c.bounds.right;
|
|
1911
|
+
break;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (yEncs.length == 0) {
|
|
1916
|
+
switch(this._cellVertAlignment) {
|
|
1917
|
+
case Alignment.Top:
|
|
1918
|
+
cdy = gridBound.top - c.bounds.top;
|
|
1919
|
+
break;
|
|
1920
|
+
case Alignment.Middle:
|
|
1921
|
+
cdy = gridBound.y - c.bounds.y;
|
|
1922
|
+
break;
|
|
1923
|
+
case Alignment.Bottom:
|
|
1924
|
+
cdy = gridBound.bottom - c.bounds.bottom;
|
|
1925
|
+
break;
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
c._doTranslate(cdx, cdy);
|
|
1902
1930
|
}
|
|
1903
|
-
return true;
|
|
1904
|
-
}
|
|
1905
1931
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1932
|
+
if (xEncs.length > 0) {
|
|
1933
|
+
//if childrens' position bound to data, compute position using the scale
|
|
1934
|
+
for (let enc of xEncs)
|
|
1935
|
+
enc._apply();
|
|
1936
|
+
} else if (wdEncs.length > 0) {
|
|
1937
|
+
let enc = wdEncs[wdEncs.length-1];
|
|
1938
|
+
if (enc._rectNegativeValues){
|
|
1939
|
+
enc._apply();
|
|
1940
|
+
}
|
|
1910
1941
|
}
|
|
1911
|
-
return true;
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
1942
|
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
if (
|
|
1921
|
-
|
|
1943
|
+
if (yEncs.length > 0) {
|
|
1944
|
+
//yEncs[yEncs.length-1]._map();
|
|
1945
|
+
// yEncs[yEncs.length-1]._apply();
|
|
1946
|
+
for (let enc of yEncs)
|
|
1947
|
+
enc._apply();
|
|
1948
|
+
} else if (htEncs.length > 0) {
|
|
1949
|
+
let enc = htEncs[htEncs.length-1];
|
|
1950
|
+
if (enc._rectNegativeValues){
|
|
1951
|
+
enc._apply();
|
|
1952
|
+
}
|
|
1922
1953
|
}
|
|
1954
|
+
|
|
1955
|
+
this.group._updateBounds();
|
|
1923
1956
|
}
|
|
1924
|
-
|
|
1925
|
-
|
|
1957
|
+
|
|
1958
|
+
//TODO: add a corresponding scene level operation, automatically relayout
|
|
1959
|
+
set rowGap(g) {
|
|
1960
|
+
this._rowGap = g;
|
|
1961
|
+
this.run();
|
|
1962
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
1926
1963
|
}
|
|
1927
|
-
return true;
|
|
1928
|
-
}
|
|
1929
1964
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
return false;
|
|
1933
|
-
if (item.parent && item.parent.layout) {
|
|
1934
|
-
let layout = item.parent.layout;
|
|
1935
|
-
if (layout.type == LayoutType.Grid && layout.numRows > 1) {
|
|
1936
|
-
return false;
|
|
1937
|
-
}
|
|
1965
|
+
get rowGap() {
|
|
1966
|
+
return this._rowGap;
|
|
1938
1967
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
1968
|
+
|
|
1969
|
+
set colGap(g) {
|
|
1970
|
+
this._colGap = g;
|
|
1971
|
+
this.run();
|
|
1972
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
1941
1973
|
}
|
|
1942
|
-
return true;
|
|
1943
|
-
}
|
|
1944
1974
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1975
|
+
get colGap() {
|
|
1976
|
+
return this._colGap;
|
|
1977
|
+
}
|
|
1947
1978
|
|
|
1948
|
-
|
|
1949
|
-
if (
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
this.canvas = document.createElement('canvas');
|
|
1979
|
+
set numCols(c) {
|
|
1980
|
+
if (c < 0 || c > this.group.children.length) {
|
|
1981
|
+
console.warn("Cannot set", c, "columns for", this.group.children.length, "items in grid");
|
|
1982
|
+
return;
|
|
1953
1983
|
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
return canvas ? canvas.getContext('2d') : null;
|
|
1960
|
-
},
|
|
1961
|
-
};
|
|
1962
|
-
|
|
1963
|
-
var SVGProvider = {
|
|
1964
|
-
svg: undefined,
|
|
1984
|
+
this._numCols = c;
|
|
1985
|
+
this._numRows = Math.ceil(this.group.children.length/c);
|
|
1986
|
+
this.run();
|
|
1987
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
1988
|
+
}
|
|
1965
1989
|
|
|
1966
|
-
|
|
1967
|
-
if (
|
|
1968
|
-
|
|
1969
|
-
if (this.
|
|
1970
|
-
this.
|
|
1990
|
+
get numCols() {
|
|
1991
|
+
if (this._numCols) {
|
|
1992
|
+
return this._numCols;
|
|
1993
|
+
} else if (this._numRows) {
|
|
1994
|
+
return Math.ceil(this.group.children.length/this._numRows);
|
|
1995
|
+
} else {
|
|
1996
|
+
return 0;
|
|
1971
1997
|
}
|
|
1972
|
-
return this.svg;
|
|
1973
1998
|
}
|
|
1974
|
-
};
|
|
1975
|
-
|
|
1976
|
-
// export function getTextWidth(text, font) {
|
|
1977
|
-
// let context = CanvasProvider.getContext();
|
|
1978
|
-
// context.font = font;
|
|
1979
|
-
// let metrics = context.measureText(text);
|
|
1980
|
-
// return metrics.width;
|
|
1981
|
-
// }
|
|
1982
1999
|
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
}
|
|
2000
|
+
set numRows(c) {
|
|
2001
|
+
if (c < 0 || c > this.group.children.length) {
|
|
2002
|
+
console.warn("Cannot set", c, "rows for", this.group.children.length, "items in grid");
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
this._numRows = c;
|
|
2006
|
+
this._numCols = Math.ceil(this.group.children.length/c);
|
|
2007
|
+
this.run();
|
|
2008
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
2009
|
+
}
|
|
1994
2010
|
|
|
1995
|
-
function getTopLevelGroup(item) {
|
|
1996
|
-
let parent = item.parent;
|
|
1997
|
-
if (parent.type == ItemType.Scene)
|
|
1998
|
-
return item;
|
|
1999
|
-
else
|
|
2000
|
-
return getTopLevelGroup(parent);
|
|
2001
|
-
}
|
|
2002
2011
|
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
if (
|
|
2007
|
-
return
|
|
2008
|
-
} else
|
|
2009
|
-
return
|
|
2010
|
-
} else if (parent.type != ItemType.Scene) {
|
|
2011
|
-
return getTopLevelCollection(parent);
|
|
2012
|
-
} else {
|
|
2013
|
-
return undefined;
|
|
2012
|
+
get numRows() {
|
|
2013
|
+
if (this._numRows) {
|
|
2014
|
+
return this._numRows;
|
|
2015
|
+
} else if (this._numCols) {
|
|
2016
|
+
return Math.ceil(this.group.children.length/this._numCols);
|
|
2017
|
+
} else
|
|
2018
|
+
return 0;
|
|
2014
2019
|
}
|
|
2015
|
-
}
|
|
2016
2020
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2021
|
+
set vertCellAlignment(v) {
|
|
2022
|
+
if (v != Alignment.Top && v != Alignment.Bottom && v != Alignment.Middle) {
|
|
2023
|
+
throw Errors.UNKOWN_ALIGNMENT;
|
|
2024
|
+
}
|
|
2025
|
+
this._cellVertAlignment = v;
|
|
2026
|
+
this.run();
|
|
2027
|
+
}
|
|
2022
2028
|
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
if (d < 0) d += 360;
|
|
2027
|
-
let r = Math.sqrt(Math.pow(x-cx, 2) + Math.pow(y-cy, 2));
|
|
2028
|
-
r = Math.round( r * 10 + Number.EPSILON ) / 10;
|
|
2029
|
-
return [d, r];
|
|
2030
|
-
}
|
|
2029
|
+
get vertCellAlignment() {
|
|
2030
|
+
return this._cellVertAlignment;
|
|
2031
|
+
}
|
|
2031
2032
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2033
|
+
set horzCellAlignment(h) {
|
|
2034
|
+
if (h != Alignment.Left && h != Alignment.Center && h != Alignment.Right) {
|
|
2035
|
+
throw Errors.UNKOWN_ALIGNMENT;
|
|
2036
|
+
}
|
|
2037
|
+
this._cellHorzAlignment = h;
|
|
2038
|
+
this.run();
|
|
2039
|
+
}
|
|
2035
2040
|
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2041
|
+
get horzCellAlignment() {
|
|
2042
|
+
return this._cellHorzAlignment;
|
|
2043
|
+
}
|
|
2039
2044
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
let peer1 = area.vertices[Vid1], peer2 = area.vertices[Vid2];
|
|
2045
|
-
if (peer1.x == peer2.x && peer1.y == peer2.y) {
|
|
2046
|
-
continue;
|
|
2045
|
+
//accepts two formats: a two-element array, or a string
|
|
2046
|
+
set direction(d) {
|
|
2047
|
+
if (Array.isArray(d) && d.length === 2) {
|
|
2048
|
+
this._dir = d;
|
|
2047
2049
|
} else {
|
|
2048
|
-
|
|
2049
|
-
return "horizontal";
|
|
2050
|
-
} else {
|
|
2051
|
-
return "vertical";
|
|
2052
|
-
}
|
|
2050
|
+
this._dir = d.split("_");
|
|
2053
2051
|
}
|
|
2052
|
+
this.run();
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
get direction() {
|
|
2056
|
+
return this._dir.join("_");
|
|
2054
2057
|
}
|
|
2055
2058
|
}
|
|
2056
2059
|
|
|
2060
|
+
GridLayout.direction = {
|
|
2061
|
+
Left2Right: "l2r",
|
|
2062
|
+
Right2Left: "r2l",
|
|
2063
|
+
Top2Bottom: "t2b",
|
|
2064
|
+
Bottom2Top: "b2t"
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2057
2067
|
/**
|
|
2058
2068
|
* Same as group in graphical design tools
|
|
2059
2069
|
**/
|
|
@@ -4006,6 +4016,7 @@
|
|
|
4006
4016
|
this.scale = createScale("time");
|
|
4007
4017
|
this.scale.isFlipped = this._flipScale;
|
|
4008
4018
|
range = [0, extent];
|
|
4019
|
+
this.scale._baseItem = this.anyItem;
|
|
4009
4020
|
}
|
|
4010
4021
|
break;
|
|
4011
4022
|
|
|
@@ -4026,6 +4037,7 @@
|
|
|
4026
4037
|
this.scale = createScale("point");
|
|
4027
4038
|
this.scale.isFlipped = this._flipScale;
|
|
4028
4039
|
range = [0, extent];
|
|
4040
|
+
this.scale._baseItem = this.anyItem;
|
|
4029
4041
|
}
|
|
4030
4042
|
break;
|
|
4031
4043
|
|
|
@@ -6188,6 +6200,8 @@
|
|
|
6188
6200
|
matches(item) {}
|
|
6189
6201
|
|
|
6190
6202
|
reposition() {
|
|
6203
|
+
if (this instanceof EncodingAxis)
|
|
6204
|
+
this._determineAxisFlip();
|
|
6191
6205
|
this._positionPath();
|
|
6192
6206
|
this._positionTicks();
|
|
6193
6207
|
this._positionLabels();
|
|
@@ -10747,12 +10761,18 @@
|
|
|
10747
10761
|
.attr("width", d => d.width).attr("height", rowGap)
|
|
10748
10762
|
.style("fill", "pink").style("opacity", 0.5)
|
|
10749
10763
|
;
|
|
10750
|
-
let
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
.attr("width", c.bounds.width).attr("height", c.bounds.height)
|
|
10764
|
+
for (let cb of cellBounds) {
|
|
10765
|
+
this._decoMap[gridId].append("rect").attr("x", cb.left).attr("y", cb.top)
|
|
10766
|
+
.attr("width", cb.width).attr("height", cb.height)
|
|
10754
10767
|
.attr("stroke", "blue").attr("stroke-width", "1px")
|
|
10755
10768
|
.attr("stroke-dasharray", "5,5").attr("fill", "none");
|
|
10769
|
+
}
|
|
10770
|
+
// let left = Math.min(...cellBounds.map(d => d.left)),
|
|
10771
|
+
// top = Math.min(...cellBounds.map(d => d.top))
|
|
10772
|
+
// this._decoMap[gridId].append("rect").attr("x", left).attr("y", top)
|
|
10773
|
+
// .attr("width", c.bounds.width).attr("height", c.bounds.height)
|
|
10774
|
+
// .attr("stroke", "blue").attr("stroke-width", "1px")
|
|
10775
|
+
// .attr("stroke-dasharray", "5,5").attr("fill", "none");
|
|
10756
10776
|
|
|
10757
10777
|
}
|
|
10758
10778
|
|
|
@@ -24324,6 +24344,14 @@
|
|
|
24324
24344
|
}
|
|
24325
24345
|
}
|
|
24326
24346
|
|
|
24347
|
+
function canFormGlyph(args) {
|
|
24348
|
+
for (let itm of args) {
|
|
24349
|
+
if (!isMark(itm))
|
|
24350
|
+
return false;
|
|
24351
|
+
}
|
|
24352
|
+
return true;
|
|
24353
|
+
}
|
|
24354
|
+
|
|
24327
24355
|
function canClassify(item) {
|
|
24328
24356
|
if (item.type !== ItemType.Collection) return false;
|
|
24329
24357
|
if (item.children.length < 2) return false;
|
|
@@ -24349,6 +24377,7 @@
|
|
|
24349
24377
|
exports.canClassify = canClassify;
|
|
24350
24378
|
exports.canDensify = canDensify;
|
|
24351
24379
|
exports.canDivide = canDivide;
|
|
24380
|
+
exports.canFormGlyph = canFormGlyph;
|
|
24352
24381
|
exports.canRepeat = canRepeat;
|
|
24353
24382
|
exports.cartesianToPolar = cartesianToPolar;
|
|
24354
24383
|
exports.createScale = createScale;
|