mascot-vis 1.11.2 → 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 +21 -21
- package/dist/mascot.js +1377 -1204
- 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.
|
|
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,1255 +273,846 @@
|
|
|
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
|
-
* zero. The value should be large enough to offset any floating point
|
|
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;
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* The epsilon to be used when performing "trigonometric" checks, such
|
|
901
|
-
* as examining cross products to check for collinearity.
|
|
902
|
-
*/
|
|
903
|
-
const TRIGONOMETRIC_EPSILON = 1e-8;
|
|
904
|
-
|
|
905
|
-
/**
|
|
906
|
-
* Checks if the value is 0, within a tolerance defined by
|
|
907
|
-
* Numerical.EPSILON.
|
|
908
|
-
*/
|
|
909
|
-
function isZero(val) {
|
|
910
|
-
return val >= -EPSILON && val <= EPSILON;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Based on basic.Point.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
914
|
-
|
|
915
|
-
class Point {
|
|
916
|
-
|
|
917
|
-
constructor(x, y) {
|
|
918
|
-
this.x = x;
|
|
919
|
-
this.y = y;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
transform(matrix) {
|
|
923
|
-
return matrix ? matrix._transformPoint(this) : this;
|
|
925
|
+
get strokeDash() {
|
|
926
|
+
return this.styles["strokeDash"];
|
|
924
927
|
}
|
|
925
928
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
subtract(point) {
|
|
931
|
-
return new Point(this.x - point.x, this.y - point.y);
|
|
929
|
+
set strokeDash(c) {
|
|
930
|
+
this.styles["strokeDash"] = c;
|
|
932
931
|
}
|
|
933
932
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
* Checks if the vector represented by this point is collinear (parallel) to
|
|
940
|
-
* another vector.
|
|
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
|
-
}
|
|
953
|
-
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
// Based on path.Segment.js, as part of Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
957
|
-
|
|
958
|
-
class Vertex {
|
|
959
|
-
|
|
960
|
-
//handles are relative to the point
|
|
961
|
-
constructor(point, parentMark, id) {
|
|
962
|
-
this.type = "vertex";
|
|
963
|
-
this._id = id;
|
|
964
|
-
this.x = point.x;
|
|
965
|
-
this.y = point.y;
|
|
966
|
-
this.dataScope = undefined;
|
|
967
|
-
this.parent = parentMark;
|
|
968
|
-
|
|
969
|
-
this.shape = undefined;
|
|
970
|
-
this.width = 0;
|
|
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;
|
|
933
|
+
_doTranslate(dx, dy) {
|
|
934
|
+
for (let v of this.vertices) {
|
|
935
|
+
v._doTranslate(dx, dy);
|
|
936
|
+
}
|
|
937
|
+
this._updateBounds();
|
|
978
938
|
}
|
|
979
939
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
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
|
+
}
|
|
988
960
|
}
|
|
961
|
+
this._updateBounds();
|
|
989
962
|
}
|
|
990
963
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
964
|
+
_updateBounds() {
|
|
965
|
+
let vx = this.vertices.map(d => d.x),
|
|
966
|
+
vy = this.vertices.map(d => d.y);
|
|
994
967
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
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;
|
|
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
|
+
}
|
|
1014
978
|
}
|
|
1015
979
|
|
|
1016
|
-
|
|
1017
|
-
let
|
|
1018
|
-
|
|
1019
|
-
|
|
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;
|
|
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
|
|
1031
984
|
}
|
|
1032
985
|
|
|
1033
|
-
|
|
1034
|
-
this.
|
|
1035
|
-
|
|
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
|
+
}
|
|
1036
995
|
}
|
|
1037
996
|
|
|
1038
|
-
|
|
1039
|
-
let
|
|
1040
|
-
if (
|
|
1041
|
-
|
|
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];
|
|
1042
1010
|
}
|
|
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;
|
|
1052
1011
|
}
|
|
1053
1012
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
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();
|
|
1057
1023
|
|
|
1058
|
-
|
|
1059
|
-
return this._polarAngle;
|
|
1024
|
+
return p._;
|
|
1060
1025
|
}
|
|
1061
|
-
|
|
1026
|
+
|
|
1027
|
+
// toSVG() {
|
|
1062
1028
|
|
|
1063
|
-
|
|
1029
|
+
// }
|
|
1064
1030
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
constructor(v1, v2, parentMark, id) {
|
|
1068
|
-
this.type = "segment";
|
|
1069
|
-
this._id = id;
|
|
1070
|
-
this.vertex1 = v1;
|
|
1071
|
-
this.vertex2 = v2;
|
|
1031
|
+
// fromSVG() {
|
|
1072
1032
|
|
|
1073
|
-
|
|
1074
|
-
this.parent = parentMark;
|
|
1075
|
-
}
|
|
1033
|
+
// }
|
|
1076
1034
|
|
|
1077
|
-
get
|
|
1078
|
-
return this.
|
|
1035
|
+
get firstVertex() {
|
|
1036
|
+
return this.vertices[0];
|
|
1079
1037
|
}
|
|
1080
1038
|
|
|
1081
|
-
|
|
1082
|
-
this.
|
|
1083
|
-
this.vertex2._doTranslate(dx, dy);
|
|
1039
|
+
get firstSegment() {
|
|
1040
|
+
return this.segments[0];
|
|
1084
1041
|
}
|
|
1085
1042
|
|
|
1086
|
-
get
|
|
1087
|
-
return
|
|
1043
|
+
get lastVertex() {
|
|
1044
|
+
return this.vertices[this.vertices.length - 1];
|
|
1088
1045
|
}
|
|
1089
1046
|
|
|
1090
|
-
get
|
|
1091
|
-
return
|
|
1047
|
+
get lastSegment() {
|
|
1048
|
+
return this.segments[this.segments.length - 1];
|
|
1092
1049
|
}
|
|
1093
|
-
}
|
|
1094
1050
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
this.anchor = undefined;
|
|
1114
|
-
|
|
1115
|
-
this.closed = false;
|
|
1116
|
-
|
|
1117
|
-
this.curveMode = "linear";
|
|
1118
|
-
|
|
1119
|
-
//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
|
|
1120
|
-
this.boundsOffsets = {top: 0, bottom: 0, left: 0, right: 0};
|
|
1121
|
-
|
|
1122
|
-
this._vxShape = undefined;
|
|
1123
|
-
this._vxWidth = 0;
|
|
1124
|
-
this._vxHeight = 0;
|
|
1125
|
-
this._vxRadius = 0;
|
|
1126
|
-
this._vxFillColor = "#555555";
|
|
1127
|
-
this._vxStrokeColor = "#aaaaaa";
|
|
1128
|
-
this._vxStrokeWidth = 0;
|
|
1129
|
-
this._vxOpacity = 1;
|
|
1130
|
-
|
|
1131
|
-
if (args !== undefined) {
|
|
1132
|
-
for (let vs of Vertex.styles){
|
|
1133
|
-
if (vs in args)
|
|
1134
|
-
this["_" + vs] = args[vs];
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
if ("vertices" in args) {
|
|
1138
|
-
this._setVertices(args["vertices"]);
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
toJSON() {
|
|
1144
|
-
let json = super.toJSON();
|
|
1145
|
-
json.type = this.type;
|
|
1146
|
-
json.id = this.id;
|
|
1147
|
-
switch (this.type) {
|
|
1148
|
-
case ItemType.Rect:
|
|
1149
|
-
json.args.width = this.width;
|
|
1150
|
-
json.args.height = this.height;
|
|
1151
|
-
json.args.top = this.top;
|
|
1152
|
-
json.args.left = this.left;
|
|
1153
|
-
break;
|
|
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;
|
|
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;
|
|
1168
1069
|
default:
|
|
1169
|
-
|
|
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];
|
|
1070
|
+
return d3__namespace.curveLinear;
|
|
1226
1071
|
}
|
|
1227
|
-
return json;
|
|
1228
1072
|
}
|
|
1229
1073
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
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;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
point = new Point(vertices[i][0], vertices[i][1]);
|
|
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
|
-
}
|
|
1249
|
-
}
|
|
1074
|
+
get vxShape(){
|
|
1075
|
+
return this._vxShape;
|
|
1076
|
+
}
|
|
1250
1077
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
//if the first vertex has the same position as the last, this path is closed
|
|
1256
|
-
let first = vertices[0], last = vertices[vertices.length - 1];
|
|
1257
|
-
if ((first[0] === last[0] && first[1] === last[1]) || this.type === ItemType.Rect) {
|
|
1258
|
-
this.closed = true;
|
|
1259
|
-
if (!("fillColor" in this.styles))
|
|
1260
|
-
this.styles["fillColor"] = "#fff";
|
|
1261
|
-
this.segments.push(new Segment(this.vertices[this.vertices.length-1], this.vertices[0], this, this.segmentCounter++));
|
|
1262
|
-
}
|
|
1078
|
+
set vxShape(s){
|
|
1079
|
+
this._vxShape = s;
|
|
1080
|
+
for (let v of this.vertices)
|
|
1081
|
+
v.shape = s;
|
|
1263
1082
|
}
|
|
1264
1083
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
target.styles = Object.assign({}, this.styles);
|
|
1268
|
-
for (let vs of Vertex.styles){
|
|
1269
|
-
if (this["_"+vs])
|
|
1270
|
-
target["_"+vs] = this["_"+vs];
|
|
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++));
|
|
1284
|
-
}
|
|
1285
|
-
if (target.closed)
|
|
1286
|
-
target.segments.push(new Segment(target.vertices[target.vertices.length-1], target.vertices[0], target, target.segmentCounter++));
|
|
1084
|
+
get vxWidth(){
|
|
1085
|
+
return this._vxWidth;
|
|
1287
1086
|
}
|
|
1288
1087
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (!this._bounds)
|
|
1294
|
-
this._updateBounds();
|
|
1295
|
-
return this._bounds;
|
|
1088
|
+
set vxWidth(s){
|
|
1089
|
+
this._vxWidth = s;
|
|
1090
|
+
for (let v of this.vertices)
|
|
1091
|
+
v.width = s;
|
|
1296
1092
|
}
|
|
1297
1093
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
*/
|
|
1301
|
-
get refBounds() {
|
|
1302
|
-
if (!this._bounds)
|
|
1303
|
-
this._updateBounds();
|
|
1304
|
-
let ht = (this._bounds.bottom + this.boundsOffsets.bottom) - (this._bounds.top - this.boundsOffsets.top),
|
|
1305
|
-
wd = this._bounds.right + this.boundsOffsets.right - (this._bounds.left - this.boundsOffsets.left);
|
|
1306
|
-
return new Rectangle(this._bounds.left - this.boundsOffsets.left, this._bounds.top - this.boundsOffsets.top, wd, ht);
|
|
1094
|
+
get vxHeight(){
|
|
1095
|
+
return this._vxHeight;
|
|
1307
1096
|
}
|
|
1308
1097
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1098
|
+
set vxHeight(s){
|
|
1099
|
+
this._vxHeight = s;
|
|
1100
|
+
for (let v of this.vertices)
|
|
1101
|
+
v.height = s;
|
|
1311
1102
|
}
|
|
1312
1103
|
|
|
1313
|
-
get
|
|
1314
|
-
return this.
|
|
1104
|
+
get vxRadius(){
|
|
1105
|
+
return this._vxRadius;
|
|
1315
1106
|
}
|
|
1316
1107
|
|
|
1317
|
-
|
|
1318
|
-
|
|
1108
|
+
set vxRadius(s){
|
|
1109
|
+
this._vxRadius = s;
|
|
1110
|
+
for (let v of this.vertices)
|
|
1111
|
+
v.radius = s;
|
|
1319
1112
|
}
|
|
1320
1113
|
|
|
1321
|
-
|
|
1322
|
-
this.
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
get strokeWidth() {
|
|
1326
|
-
return this.styles["strokeWidth"];
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
set strokeWidth(c) {
|
|
1330
|
-
this.styles["strokeWidth"] = c;
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
get fillColor() {
|
|
1334
|
-
return this.styles["fillColor"];
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
set fillColor(c) {
|
|
1338
|
-
this.styles["fillColor"] = c;
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
get strokeDash() {
|
|
1342
|
-
return this.styles["strokeDash"];
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
set strokeDash(c) {
|
|
1346
|
-
this.styles["strokeDash"] = c;
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
_doTranslate(dx, dy) {
|
|
1350
|
-
for (let v of this.vertices) {
|
|
1351
|
-
v._doTranslate(dx, dy);
|
|
1352
|
-
}
|
|
1353
|
-
this._updateBounds();
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
//by default, with respect to the center of bounds
|
|
1357
|
-
resize(wd, ht, xRef, yRef) {
|
|
1358
|
-
let bounds = this.bounds, bWidth = bounds.width === 0 ? 1 : bounds.width, bHeight = bounds.height === 0 ? 1 : bounds.height;
|
|
1359
|
-
if (xRef === "right") {
|
|
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
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
this._updateBounds();
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
_updateBounds() {
|
|
1381
|
-
let vx = this.vertices.map(d => d.x),
|
|
1382
|
-
vy = this.vertices.map(d => d.y);
|
|
1383
|
-
|
|
1384
|
-
let left = Math.min(...vx), top = Math.min(...vy), right = Math.max(...vx), btm = Math.max(...vy);
|
|
1385
|
-
this._bounds = new Rectangle(left, top, right - left, btm - top);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
addVertex(x, y, i) {
|
|
1389
|
-
let vertex = new Vertex(new Point(x, y), this, this.vertexCounter++);
|
|
1390
|
-
this.vertices.splice(i, 0, vertex);
|
|
1391
|
-
//TODO: handle segments
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
sortVertices(channel, descending) {
|
|
1395
|
-
this.vertices.sort((a,b) => a[channel] - b[channel]);
|
|
1396
|
-
if (descending)
|
|
1397
|
-
this.vertices.reverse();
|
|
1398
|
-
for (let i = 0; i < this.segments.length; i++) {
|
|
1399
|
-
let segment = this.segments[i];
|
|
1400
|
-
segment.vertex1 = this.vertices[i];
|
|
1401
|
-
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
sortVerticesByData(field, descending, order) {
|
|
1406
|
-
let f;
|
|
1407
|
-
if (order)
|
|
1408
|
-
f = (a, b) => order.indexOf(a.dataScope.getFieldValue(field)) - order.indexOf(b.dataScope.getFieldValue(field));
|
|
1409
|
-
else
|
|
1410
|
-
f = (a, b) => (a.dataScope.getFieldValue(field) < b.dataScope.getFieldValue(field) ? -1 : 1 );
|
|
1411
|
-
this.vertices.sort(f);
|
|
1412
|
-
if (descending)
|
|
1413
|
-
this.vertices.reverse();
|
|
1414
|
-
for (let i = 0; i < this.segments.length; i++) {
|
|
1415
|
-
let segment = this.segments[i];
|
|
1416
|
-
segment.vertex1 = this.vertices[i];
|
|
1417
|
-
segment.vertex2 = this.vertices[(i+1)%this.vertices.length];
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
getSVGPathData() {
|
|
1422
|
-
let p = d3__namespace.path();
|
|
1423
|
-
let curve = this._getD3CurveFunction(this.curveMode)(p);
|
|
1424
|
-
curve.lineStart();
|
|
1425
|
-
for (let vertex of this.vertices) {
|
|
1426
|
-
curve.point(vertex.x, vertex.y);
|
|
1427
|
-
}
|
|
1428
|
-
if (this.closed)
|
|
1429
|
-
curve.point(this.vertices[0].x, this.vertices[0].y);
|
|
1430
|
-
curve.lineEnd();
|
|
1431
|
-
|
|
1432
|
-
return p._;
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
// toSVG() {
|
|
1436
|
-
|
|
1437
|
-
// }
|
|
1438
|
-
|
|
1439
|
-
// fromSVG() {
|
|
1440
|
-
|
|
1441
|
-
// }
|
|
1442
|
-
|
|
1443
|
-
get firstVertex() {
|
|
1444
|
-
return this.vertices[0];
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
get firstSegment() {
|
|
1448
|
-
return this.segments[0];
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
|
-
get lastVertex() {
|
|
1452
|
-
return this.vertices[this.vertices.length - 1];
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
get lastSegment() {
|
|
1456
|
-
return this.segments[this.segments.length - 1];
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
_getD3CurveFunction(v){
|
|
1460
|
-
switch(v) {
|
|
1461
|
-
case CurveMode.Natural:
|
|
1462
|
-
return d3__namespace.curveNatural;
|
|
1463
|
-
case CurveMode.Basis:
|
|
1464
|
-
return d3__namespace.curveBasis;
|
|
1465
|
-
case CurveMode.BumpX:
|
|
1466
|
-
return d3__namespace.curveBumpX;
|
|
1467
|
-
case CurveMode.BumpY:
|
|
1468
|
-
return d3__namespace.curveBumpY;
|
|
1469
|
-
case CurveMode.Linear:
|
|
1470
|
-
return d3__namespace.curveLinear;
|
|
1471
|
-
case CurveMode.Step:
|
|
1472
|
-
return d3__namespace.curveStep;
|
|
1473
|
-
case CurveMode.CatmullRom:
|
|
1474
|
-
return d3__namespace.curveCatmullRom;
|
|
1475
|
-
case CurveMode.Cardinal:
|
|
1476
|
-
return d3__namespace.curveCardinal;
|
|
1477
|
-
default:
|
|
1478
|
-
return d3__namespace.curveLinear;
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
get vxShape(){
|
|
1483
|
-
return this._vxShape;
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
set vxShape(s){
|
|
1487
|
-
this._vxShape = s;
|
|
1488
|
-
for (let v of this.vertices)
|
|
1489
|
-
v.shape = s;
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
get vxWidth(){
|
|
1493
|
-
return this._vxWidth;
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
set vxWidth(s){
|
|
1497
|
-
this._vxWidth = s;
|
|
1498
|
-
for (let v of this.vertices)
|
|
1499
|
-
v.width = s;
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
get vxHeight(){
|
|
1503
|
-
return this._vxHeight;
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
set vxHeight(s){
|
|
1507
|
-
this._vxHeight = s;
|
|
1508
|
-
for (let v of this.vertices)
|
|
1509
|
-
v.height = s;
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
get vxRadius(){
|
|
1513
|
-
return this._vxRadius;
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
set vxRadius(s){
|
|
1517
|
-
this._vxRadius = s;
|
|
1518
|
-
for (let v of this.vertices)
|
|
1519
|
-
v.radius = s;
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
get vxFillColor(){
|
|
1523
|
-
return this._vxFillColor;
|
|
1114
|
+
get vxFillColor(){
|
|
1115
|
+
return this._vxFillColor;
|
|
1524
1116
|
}
|
|
1525
1117
|
|
|
1526
1118
|
set vxFillColor(s){
|
|
@@ -1744,6 +1336,18 @@
|
|
|
1744
1336
|
return undefined;
|
|
1745
1337
|
}
|
|
1746
1338
|
|
|
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;
|
|
1347
|
+
}
|
|
1348
|
+
return undefined;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1747
1351
|
function getCellBoundsInGridLayout(item) {
|
|
1748
1352
|
let itm = item, parent = item.parent;
|
|
1749
1353
|
while (parent && parent.type != ItemType.Scene) {
|
|
@@ -1789,6 +1393,10 @@
|
|
|
1789
1393
|
}
|
|
1790
1394
|
}
|
|
1791
1395
|
|
|
1396
|
+
function sameClass(item1, item2) {
|
|
1397
|
+
return getEncodingKey(item1).split("_")[0] === getEncodingKey(item2).split("_")[0];
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1792
1400
|
function getParents(items) {
|
|
1793
1401
|
let result = [];
|
|
1794
1402
|
for (let p of items) {
|
|
@@ -1930,106 +1538,532 @@
|
|
|
1930
1538
|
return this.canvas;
|
|
1931
1539
|
},
|
|
1932
1540
|
|
|
1933
|
-
getContext: function() {
|
|
1934
|
-
var canvas = this.getCanvas();
|
|
1935
|
-
return canvas ? canvas.getContext('2d') : null;
|
|
1936
|
-
},
|
|
1937
|
-
};
|
|
1541
|
+
getContext: function() {
|
|
1542
|
+
var canvas = this.getCanvas();
|
|
1543
|
+
return canvas ? canvas.getContext('2d') : null;
|
|
1544
|
+
},
|
|
1545
|
+
};
|
|
1546
|
+
|
|
1547
|
+
var SVGProvider = {
|
|
1548
|
+
svg: undefined,
|
|
1549
|
+
|
|
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;
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
|
|
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
|
+
// }
|
|
1566
|
+
|
|
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
|
+
}
|
|
1578
|
+
|
|
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;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
|
|
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
|
+
}
|
|
1606
|
+
|
|
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
|
+
}
|
|
1615
|
+
|
|
1616
|
+
function degree2radian(d){
|
|
1617
|
+
return d * Math.PI/180;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
function radian2degree(r){
|
|
1621
|
+
return r * 180 / Math.PI;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
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
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
class Layout {
|
|
1642
|
+
|
|
1643
|
+
constructor(args){
|
|
1644
|
+
this.group = undefined;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
run(){}
|
|
1648
|
+
|
|
1649
|
+
clone(){}
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
class GridLayout extends Layout {
|
|
1653
|
+
|
|
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;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
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;
|
|
1678
|
+
|
|
1679
|
+
}
|
|
1680
|
+
|
|
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;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
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
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
|
|
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);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
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);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
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;
|
|
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];
|
|
1749
|
+
}
|
|
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;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
let cb = [], cellCount = numRows * numCols;
|
|
1762
|
+
|
|
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;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
return cb;
|
|
1849
|
+
|
|
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 {
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
run() {
|
|
1882
|
+
if (this.group == undefined|| !this.group.children || this.group.children.length === 0)
|
|
1883
|
+
return;
|
|
1884
|
+
|
|
1885
|
+
let cellBounds = this.cellBounds;
|
|
1886
|
+
|
|
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];
|
|
1894
|
+
|
|
1895
|
+
let dx = gridBound.x - c.bounds.x,
|
|
1896
|
+
dy = gridBound.y - c.bounds.y;
|
|
1897
|
+
c._doTranslate(dx, dy);
|
|
1898
|
+
|
|
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);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
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
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
|
|
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
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
this.group._updateBounds();
|
|
1956
|
+
}
|
|
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);
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
get rowGap() {
|
|
1966
|
+
return this._rowGap;
|
|
1967
|
+
}
|
|
1938
1968
|
|
|
1939
|
-
|
|
1940
|
-
|
|
1969
|
+
set colGap(g) {
|
|
1970
|
+
this._colGap = g;
|
|
1971
|
+
this.run();
|
|
1972
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
1973
|
+
}
|
|
1941
1974
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1975
|
+
get colGap() {
|
|
1976
|
+
return this._colGap;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
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;
|
|
1947
1983
|
}
|
|
1948
|
-
|
|
1984
|
+
this._numCols = c;
|
|
1985
|
+
this._numRows = Math.ceil(this.group.children.length/c);
|
|
1986
|
+
this.run();
|
|
1987
|
+
this.group.getScene()._relayoutAncestors(this.group);
|
|
1949
1988
|
}
|
|
1950
|
-
};
|
|
1951
1989
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
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;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1958
1999
|
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
}
|
|
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
|
+
}
|
|
1970
2010
|
|
|
1971
|
-
function getTopLevelGroup(item) {
|
|
1972
|
-
let parent = item.parent;
|
|
1973
|
-
if (parent.type == ItemType.Scene)
|
|
1974
|
-
return item;
|
|
1975
|
-
else
|
|
1976
|
-
return getTopLevelGroup(parent);
|
|
1977
|
-
}
|
|
1978
2011
|
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
if (
|
|
1983
|
-
return
|
|
1984
|
-
} else
|
|
1985
|
-
return
|
|
1986
|
-
} else if (parent.type != ItemType.Scene) {
|
|
1987
|
-
return getTopLevelCollection(parent);
|
|
1988
|
-
} else {
|
|
1989
|
-
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;
|
|
1990
2019
|
}
|
|
1991
|
-
}
|
|
1992
2020
|
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
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
|
+
}
|
|
1998
2028
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
if (d < 0) d += 360;
|
|
2003
|
-
let r = Math.sqrt(Math.pow(x-cx, 2) + Math.pow(y-cy, 2));
|
|
2004
|
-
r = Math.round( r * 10 + Number.EPSILON ) / 10;
|
|
2005
|
-
return [d, r];
|
|
2006
|
-
}
|
|
2029
|
+
get vertCellAlignment() {
|
|
2030
|
+
return this._cellVertAlignment;
|
|
2031
|
+
}
|
|
2007
2032
|
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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
|
+
}
|
|
2011
2040
|
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2041
|
+
get horzCellAlignment() {
|
|
2042
|
+
return this._cellHorzAlignment;
|
|
2043
|
+
}
|
|
2015
2044
|
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
let peer1 = area.vertices[Vid1], peer2 = area.vertices[Vid2];
|
|
2021
|
-
if (peer1.x == peer2.x && peer1.y == peer2.y) {
|
|
2022
|
-
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;
|
|
2023
2049
|
} else {
|
|
2024
|
-
|
|
2025
|
-
return "horizontal";
|
|
2026
|
-
} else {
|
|
2027
|
-
return "vertical";
|
|
2028
|
-
}
|
|
2050
|
+
this._dir = d.split("_");
|
|
2029
2051
|
}
|
|
2052
|
+
this.run();
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
get direction() {
|
|
2056
|
+
return this._dir.join("_");
|
|
2030
2057
|
}
|
|
2031
2058
|
}
|
|
2032
2059
|
|
|
2060
|
+
GridLayout.direction = {
|
|
2061
|
+
Left2Right: "l2r",
|
|
2062
|
+
Right2Left: "r2l",
|
|
2063
|
+
Top2Bottom: "t2b",
|
|
2064
|
+
Bottom2Top: "b2t"
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2033
2067
|
/**
|
|
2034
2068
|
* Same as group in graphical design tools
|
|
2035
2069
|
**/
|
|
@@ -2470,6 +2504,10 @@
|
|
|
2470
2504
|
_updateTuples(field, value) {
|
|
2471
2505
|
this._tuples = this._tuples.filter(d => d[field] == value);
|
|
2472
2506
|
}
|
|
2507
|
+
|
|
2508
|
+
get tuples() {
|
|
2509
|
+
return this._tuples;
|
|
2510
|
+
}
|
|
2473
2511
|
}
|
|
2474
2512
|
|
|
2475
2513
|
function repeatItem(scene, compnt, field, datatable, callback) {
|
|
@@ -2756,13 +2794,22 @@
|
|
|
2756
2794
|
run() {
|
|
2757
2795
|
if (this.group == undefined || !this.group.children || this.group.children.length === 0)
|
|
2758
2796
|
return;
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2797
|
+
let leafMark = getLeafMarks(this.group)[0];
|
|
2798
|
+
switch (leafMark.type) {
|
|
2799
|
+
case ItemType.Area:
|
|
2800
|
+
this._stackAreas();
|
|
2801
|
+
break;
|
|
2802
|
+
case ItemType.Arc:
|
|
2803
|
+
case ItemType.Pie:
|
|
2804
|
+
if (leafMark.parent === this.group)
|
|
2805
|
+
this._stackArcs();
|
|
2806
|
+
break;
|
|
2807
|
+
case ItemType.Rect:
|
|
2808
|
+
case ItemType.Image:
|
|
2809
|
+
case ItemType.Circle:
|
|
2810
|
+
this._stackRects();
|
|
2811
|
+
break;
|
|
2812
|
+
}
|
|
2766
2813
|
}
|
|
2767
2814
|
|
|
2768
2815
|
set vertCellAlignment(v) {
|
|
@@ -2818,6 +2865,8 @@
|
|
|
2818
2865
|
switch (compnt.type) {
|
|
2819
2866
|
case ItemType.Line:
|
|
2820
2867
|
return _doLineDivide(scene, compnt, f, datatable);
|
|
2868
|
+
case ItemType.Path:
|
|
2869
|
+
return _doPathDivide(scene, compnt, f, datatable);
|
|
2821
2870
|
case ItemType.Circle:
|
|
2822
2871
|
return _doCircleDivide(scene, compnt, orientation, f, datatable);
|
|
2823
2872
|
case ItemType.Rect:
|
|
@@ -2892,6 +2941,57 @@
|
|
|
2892
2941
|
return toReturn;
|
|
2893
2942
|
}
|
|
2894
2943
|
|
|
2944
|
+
function _doPathDivide(scene, compnt, field, datatable) {
|
|
2945
|
+
let peers = getPeers(compnt, scene);
|
|
2946
|
+
let toReturn;
|
|
2947
|
+
let ds = datatable.getFieldSummary(field).unique.map(d => new DataScope(datatable).cross(field, d));
|
|
2948
|
+
|
|
2949
|
+
let line2Scopes = {}, max = 0;
|
|
2950
|
+
for (let p of peers) {
|
|
2951
|
+
let scopes = ds;
|
|
2952
|
+
if (p.dataScope) {
|
|
2953
|
+
scopes = ds.map(d => d.merge(p.dataScope));
|
|
2954
|
+
scopes = scopes.filter(d => !d.isEmpty());
|
|
2955
|
+
}
|
|
2956
|
+
if (scopes.length > max)
|
|
2957
|
+
max = scopes.length;
|
|
2958
|
+
line2Scopes[p.id] = scopes;
|
|
2959
|
+
}
|
|
2960
|
+
let collClassId;
|
|
2961
|
+
for (let p of peers) {
|
|
2962
|
+
let coll = scene.collection();
|
|
2963
|
+
if (collClassId == undefined)
|
|
2964
|
+
collClassId = coll.id;
|
|
2965
|
+
coll.classId = collClassId;
|
|
2966
|
+
coll.dataScope = p.dataScope;
|
|
2967
|
+
|
|
2968
|
+
let parent = p.parent;
|
|
2969
|
+
//let index = parent.children.indexOf(p) - 1;
|
|
2970
|
+
parent.addChild(coll);
|
|
2971
|
+
|
|
2972
|
+
let scopes = line2Scopes[p.id];
|
|
2973
|
+
let x1 = p.bounds.left, y1 = p.bounds.top, x2 = p.bounds.right, y2 = p.bounds.bottom;
|
|
2974
|
+
|
|
2975
|
+
for (let i = 0; i < scopes.length; i++) {
|
|
2976
|
+
let c = scene.mark("line", {x1: x1 + (x2 - x1) * i /max, x2: x1 + (x2 - x1) * (i + 1)/max, y1: y1 + (y2 - y1) * i /max, y2: y1 + (y2 - y1) * (i + 1)/max});
|
|
2977
|
+
c.classId = compnt.id;
|
|
2978
|
+
c.dataScope = scopes[i];
|
|
2979
|
+
coll.addChild(c);
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
parent.removeChild(p);
|
|
2983
|
+
|
|
2984
|
+
if (p == compnt)
|
|
2985
|
+
toReturn = coll;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
let f = compnt.firstVertex.dataScope.fields[0];
|
|
2989
|
+
scene.densify(toReturn.firstChild, datatable, {field: f});
|
|
2990
|
+
|
|
2991
|
+
|
|
2992
|
+
return toReturn;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2895
2995
|
|
|
2896
2996
|
|
|
2897
2997
|
function _doRectDivide(scene, compnt, o, field, datatable) {
|
|
@@ -3916,6 +4016,7 @@
|
|
|
3916
4016
|
this.scale = createScale("time");
|
|
3917
4017
|
this.scale.isFlipped = this._flipScale;
|
|
3918
4018
|
range = [0, extent];
|
|
4019
|
+
this.scale._baseItem = this.anyItem;
|
|
3919
4020
|
}
|
|
3920
4021
|
break;
|
|
3921
4022
|
|
|
@@ -3936,6 +4037,7 @@
|
|
|
3936
4037
|
this.scale = createScale("point");
|
|
3937
4038
|
this.scale.isFlipped = this._flipScale;
|
|
3938
4039
|
range = [0, extent];
|
|
4040
|
+
this.scale._baseItem = this.anyItem;
|
|
3939
4041
|
}
|
|
3940
4042
|
break;
|
|
3941
4043
|
|
|
@@ -3958,8 +4060,11 @@
|
|
|
3958
4060
|
this.scale = createScale(this.scaleType);
|
|
3959
4061
|
this.scale.isFlipped = this._flipScale;
|
|
3960
4062
|
this.scale.includeZero = this._includeZero;
|
|
3961
|
-
//domain = this._includeZero ? [0, max] : [min, max];
|
|
3962
4063
|
range = [0, extent];
|
|
4064
|
+
//remember the item that was used to first create this scale,
|
|
4065
|
+
//so that when the scale is reused later, we can refer to the base item
|
|
4066
|
+
//to get absoluate positions
|
|
4067
|
+
this.scale._baseItem = this.anyItem;
|
|
3963
4068
|
}
|
|
3964
4069
|
if (domain[0] == domain[1])
|
|
3965
4070
|
domain[1] = domain[0] * 1.1;
|
|
@@ -3980,9 +4085,26 @@
|
|
|
3980
4085
|
for (let enc of this.scale.encodings)
|
|
3981
4086
|
items = items.concat(enc.items);
|
|
3982
4087
|
if (channel == "x") {
|
|
3983
|
-
let layout = getClosestLayout(this.anyItem, "grid");
|
|
4088
|
+
//let layout = getClosestLayout(this.anyItem, "grid");
|
|
3984
4089
|
//let layout = getTopLevelCollection(this.anyItem) ? getTopLevelCollection(this.anyItem).layout : getClosestLayout(this.anyItem);
|
|
3985
|
-
|
|
4090
|
+
let layout = getClosestLayout(this.anyItem, "grid"), baseLayout = this.scale._baseItem ? getClosestLayout(this.scale._baseItem, "grid"): undefined;
|
|
4091
|
+
if (this.scale._baseItem && !sameClass(this.anyItem, this.scale._baseItem) && layout && baseLayout && layout.numRows === baseLayout.numRows && layout.numCols === baseLayout.numCols) {
|
|
4092
|
+
let tx = baseLayout.group.bounds.left - layout.group.bounds.left,
|
|
4093
|
+
ty = 0;
|
|
4094
|
+
layout.group.getScene().translate(layout.group, tx, ty);
|
|
4095
|
+
layout._colGap = baseLayout.colGap;
|
|
4096
|
+
let cellIndices = this.items.map(d => getCellIndexInLayout(d)),
|
|
4097
|
+
baseCellBounds = baseLayout.cellBounds;
|
|
4098
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
4099
|
+
let itm = this.items[i];
|
|
4100
|
+
let dx = baseCellBounds[cellIndices[i]].left + this.scale.map(this.data[i]) - itm[channel],
|
|
4101
|
+
dy = 0;
|
|
4102
|
+
itm._doTranslate(dx, dy);
|
|
4103
|
+
if (itm.type == "vertex" || itm.type == "segment")
|
|
4104
|
+
itm.parent._updateBounds();
|
|
4105
|
+
}
|
|
4106
|
+
this.anyItem.parent.getScene()._updateAncestorBounds(this.anyItem, this.items);
|
|
4107
|
+
} else if (layout && layout.type == LayoutType.Grid){
|
|
3986
4108
|
//do not use scale.offset, use cell bounds
|
|
3987
4109
|
for (let i = 0; i < this.items.length; i++) {
|
|
3988
4110
|
let itm = this.items[i], itmCb = getCellBoundsInLayout(itm);
|
|
@@ -4031,9 +4153,27 @@
|
|
|
4031
4153
|
}
|
|
4032
4154
|
|
|
4033
4155
|
} else {//channel y
|
|
4034
|
-
let layout = getClosestLayout(this.anyItem, "grid");
|
|
4035
4156
|
//let layout = getTopLevelCollection(this.anyItem) ? getTopLevelCollection(this.anyItem).layout : getClosestLayout(this.anyItem);
|
|
4036
|
-
|
|
4157
|
+
let layout = getClosestLayout(this.anyItem, "grid"), baseLayout = this.scale._baseItem ? getClosestLayout(this.scale._baseItem, "grid"): undefined;
|
|
4158
|
+
if (this.scale._baseItem && !sameClass(this.anyItem, this.scale._baseItem) && layout && baseLayout && layout.numRows === baseLayout.numRows && layout.numCols === baseLayout.numCols) {
|
|
4159
|
+
//if (this.scale._baseItem && !sameClass(this.anyItem, this.scale._baseItem) && baseLayout && baseLayout.numRows === 1) {
|
|
4160
|
+
//let peers = getPeers(this.scale._baseItem, this.scale._baseItem.parent.getScene());
|
|
4161
|
+
let tx = 0,
|
|
4162
|
+
ty = baseLayout.group.bounds.top - layout.group.bounds.top;
|
|
4163
|
+
layout.group.getScene().translate(layout.group, tx, ty);
|
|
4164
|
+
layout._rowGap = baseLayout.rowGap;
|
|
4165
|
+
let cellIndices = this.items.map(d => getCellIndexInLayout(d)),
|
|
4166
|
+
baseCellBounds = baseLayout.cellBounds;
|
|
4167
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
4168
|
+
let itm = this.items[i];
|
|
4169
|
+
let dx = 0,
|
|
4170
|
+
dy = baseCellBounds[cellIndices[i]].bottom - this.scale.map(this.data[i]) - itm[channel];
|
|
4171
|
+
itm._doTranslate(dx, dy);
|
|
4172
|
+
if (itm.type == "vertex" || itm.type == "segment")
|
|
4173
|
+
itm.parent._updateBounds();
|
|
4174
|
+
}
|
|
4175
|
+
this.anyItem.parent.getScene()._updateAncestorBounds(this.anyItem, this.items);
|
|
4176
|
+
} else if (layout && layout.type == LayoutType.Grid){
|
|
4037
4177
|
let cellBounds = this.items.map(d => getCellBoundsInLayout(d));
|
|
4038
4178
|
for (let i = 0; i < this.items.length; i++) {
|
|
4039
4179
|
let itm = this.items[i];
|
|
@@ -6060,6 +6200,8 @@
|
|
|
6060
6200
|
matches(item) {}
|
|
6061
6201
|
|
|
6062
6202
|
reposition() {
|
|
6203
|
+
if (this instanceof EncodingAxis)
|
|
6204
|
+
this._determineAxisFlip();
|
|
6063
6205
|
this._positionPath();
|
|
6064
6206
|
this._positionTicks();
|
|
6065
6207
|
this._positionLabels();
|
|
@@ -6587,6 +6729,7 @@
|
|
|
6587
6729
|
this._orientation = "orientation" in args ? args["orientation"] :
|
|
6588
6730
|
this._channel === "x" || this._channel == "width" ? "bottom" : "left";
|
|
6589
6731
|
this._posArg = this._channel == "x" || this._channel == "width"? args["pathY"] : args["pathX"];
|
|
6732
|
+
this._padding = [ItemType.Line, ItemType.Path].indexOf(items[0].type) >= 0 ? 10 : 0;
|
|
6590
6733
|
|
|
6591
6734
|
this._item = items[0];
|
|
6592
6735
|
this._items = items;
|
|
@@ -6738,22 +6881,24 @@
|
|
|
6738
6881
|
let num = this._channel == "x" ? this._mlayout.numRows : this._mlayout.numCols;
|
|
6739
6882
|
if (this._channel == "x") {
|
|
6740
6883
|
let left = cb[0].left, numCols = this._mlayout.numCols;
|
|
6884
|
+
let padding = this._orientation === "bottom" ? this._padding : - this._padding;
|
|
6741
6885
|
for (let r = 0; r < num; r++){
|
|
6742
6886
|
this._rules.children[r]._setVertices([
|
|
6743
|
-
[left, this._posArg ? cb[r * numCols][this._orientation] + this._posArg - cb[0][this._orientation] : cb[r * numCols][this._orientation] ],
|
|
6744
|
-
[left + cb[0].width * numCols + this._mlayout.colGap * (numCols - 1), this._posArg ? cb[r * numCols][this._orientation] + this._posArg - cb[0][this._orientation] : cb[r * numCols][this._orientation]]
|
|
6887
|
+
[left, this._posArg ? cb[r * numCols][this._orientation] + this._posArg - cb[0][this._orientation] : cb[r * numCols][this._orientation] + padding],
|
|
6888
|
+
[left + cb[0].width * numCols + this._mlayout.colGap * (numCols - 1), this._posArg ? cb[r * numCols][this._orientation] + this._posArg - cb[0][this._orientation] : cb[r * numCols][this._orientation] + padding]
|
|
6745
6889
|
]);
|
|
6746
6890
|
}
|
|
6747
6891
|
} else {
|
|
6748
6892
|
let top = cb[0].top, numRows = this._mlayout.numRows;
|
|
6893
|
+
let padding = this._orientation === "left" ? this._padding : - this._padding;
|
|
6749
6894
|
for (let c = 0; c < num; c++){
|
|
6750
6895
|
// this._rules.children[c]._setVertices([
|
|
6751
6896
|
// [this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : cb[c * numRows][this._orientation], top ],
|
|
6752
6897
|
// [this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : cb[c * numRows][this._orientation], top + cb[0].height * numRows + this._mlayout.rowGap * (numRows - 1), ]
|
|
6753
6898
|
// ]);
|
|
6754
6899
|
this._rules.children[c]._setVertices([
|
|
6755
|
-
[this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : this._mlayout.group.bounds[this._orientation], top ],
|
|
6756
|
-
[this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : this._mlayout.group.bounds[this._orientation], top + cb[0].height * numRows + this._mlayout.rowGap * (numRows - 1)]
|
|
6900
|
+
[this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : this._mlayout.group.bounds[this._orientation] - padding, top ],
|
|
6901
|
+
[this._posArg ? cb[c * numRows][this._orientation] + this._posArg - cb[0][this._orientation] : this._mlayout.group.bounds[this._orientation] - padding, top + cb[0].height * numRows + this._mlayout.rowGap * (numRows - 1)]
|
|
6757
6902
|
]);
|
|
6758
6903
|
}
|
|
6759
6904
|
}
|
|
@@ -6780,9 +6925,10 @@
|
|
|
6780
6925
|
let cb = this._mlayout.cellBounds;
|
|
6781
6926
|
if (this._channel == "x") {
|
|
6782
6927
|
let dir = this._orientation == "bottom" ? 1 : -1;
|
|
6928
|
+
let padding = this._orientation === "bottom" ? this._padding : - this._padding;
|
|
6783
6929
|
for (let [i, t] of this._ticks.children.entries()) {
|
|
6784
6930
|
let pos = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + this._tickOffset * dir :
|
|
6785
|
-
cb[i][this._orientation] + this._tickOffset * dir;
|
|
6931
|
+
cb[i][this._orientation] + this._tickOffset * dir + padding;
|
|
6786
6932
|
t._setVertices([
|
|
6787
6933
|
[cb[i].x, pos],
|
|
6788
6934
|
[cb[i].x, pos + dir * this._tickSize]
|
|
@@ -6791,11 +6937,12 @@
|
|
|
6791
6937
|
}
|
|
6792
6938
|
} else if (this._channel == "y"){
|
|
6793
6939
|
let dir = this._orientation == "left" ? -1 : 1;
|
|
6940
|
+
let padding = this._orientation === "left" ? this._padding : - this._padding;
|
|
6794
6941
|
for (let [i, t] of this._ticks.children.entries()) {
|
|
6795
6942
|
// let xPos = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + this._tickOffset * dir :
|
|
6796
6943
|
// cb[i][this._orientation] + this._tickOffset * dir,
|
|
6797
6944
|
let xPos = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + this._tickOffset * dir :
|
|
6798
|
-
this._mlayout.group.bounds[this._orientation] + this._tickOffset * dir,
|
|
6945
|
+
this._mlayout.group.bounds[this._orientation] + this._tickOffset * dir - padding,
|
|
6799
6946
|
yPos = this._tickAnchor == "middle" ? cb[i].y : cb[i][this._tickAnchor];
|
|
6800
6947
|
t._setVertices([
|
|
6801
6948
|
[xPos, yPos],
|
|
@@ -6813,10 +6960,11 @@
|
|
|
6813
6960
|
if (this._channel == "x") {
|
|
6814
6961
|
let anchor = this._orientation == "bottom" ? ["center", "top"] : ["center", "bottom"],
|
|
6815
6962
|
offset = this._orientation == "bottom" ? this._labelOffset : -this._labelOffset;
|
|
6963
|
+
let padding = this._orientation === "bottom" ? this._padding : - this._padding;
|
|
6816
6964
|
for (let [i, l] of this._labels.children.entries()) {
|
|
6817
6965
|
l.x = cb[i].x;
|
|
6818
6966
|
l.y = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + offset :
|
|
6819
|
-
cb[i][this._orientation] + offset;
|
|
6967
|
+
cb[i][this._orientation] + offset + padding;
|
|
6820
6968
|
l.anchor = anchor;
|
|
6821
6969
|
if (this._labelRotation){
|
|
6822
6970
|
l._rotate = [this._labelRotation, l.x, l.y];
|
|
@@ -6827,11 +6975,12 @@
|
|
|
6827
6975
|
} else if (this._channel == "y"){
|
|
6828
6976
|
let anchor = this._orientation == "left" ? ["right", "middle"] : ["left", "middle"],
|
|
6829
6977
|
offset = this._orientation == "left" ? - this._labelOffset : this._labelOffset;
|
|
6978
|
+
let padding = this._orientation === "left" ? this._padding : - this._padding;
|
|
6830
6979
|
for (let [i, l] of this._labels.children.entries()) {
|
|
6831
6980
|
// l.x = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + offset
|
|
6832
6981
|
// : cb[i][this._orientation] + offset;
|
|
6833
6982
|
l.x = this._posArg ? cb[i][this._orientation] + this._posArg - cb[0][this._orientation] + offset
|
|
6834
|
-
: this._mlayout.group.bounds[this._orientation] + offset;
|
|
6983
|
+
: this._mlayout.group.bounds[this._orientation] + offset - padding;
|
|
6835
6984
|
l.y = this._tickAnchor == "middle" ? cb[i].y : cb[i][this._tickAnchor];
|
|
6836
6985
|
l.anchor = anchor;
|
|
6837
6986
|
if (this._labelRotation) {
|
|
@@ -6871,7 +7020,8 @@
|
|
|
6871
7020
|
}
|
|
6872
7021
|
|
|
6873
7022
|
matches(item) {
|
|
6874
|
-
return
|
|
7023
|
+
return sameClass(this._item, item);
|
|
7024
|
+
//return getEncodingKey(this._item).split("_")[0] === getEncodingKey(item).split("_")[0];
|
|
6875
7025
|
}
|
|
6876
7026
|
}
|
|
6877
7027
|
|
|
@@ -6998,17 +7148,18 @@
|
|
|
6998
7148
|
for (let i = 0; i < uniqueVals.length; i+= Math.ceil(uniqueVals.length/10))
|
|
6999
7149
|
stops.push(uniqueVals[i]);
|
|
7000
7150
|
} else {
|
|
7001
|
-
let
|
|
7151
|
+
let incr = (domain[1] - domain[0])/9;
|
|
7002
7152
|
for (let i = 0; i < 10; i++)
|
|
7003
|
-
stops.push(domain[0] + i *
|
|
7004
|
-
let decimalPlaces = 0;
|
|
7005
|
-
while (interval < 1) {
|
|
7006
|
-
interval *= 10;
|
|
7007
|
-
decimalPlaces++;
|
|
7008
|
-
}
|
|
7009
|
-
stops = stops.map(d => d.toFixed(decimalPlaces));
|
|
7153
|
+
stops.push(domain[0] + i * incr);
|
|
7010
7154
|
}
|
|
7011
7155
|
}
|
|
7156
|
+
//determine decimal places
|
|
7157
|
+
let decimalPlaces = 0, interval = (stops[stops.length - 1] - stops[0])/stops.length;
|
|
7158
|
+
while (interval < 1) {
|
|
7159
|
+
interval *= 10;
|
|
7160
|
+
decimalPlaces++;
|
|
7161
|
+
}
|
|
7162
|
+
stops = stops.map(d => d.toFixed(decimalPlaces));
|
|
7012
7163
|
if (this._orientation == Orientation.Vertical) {
|
|
7013
7164
|
gradient = new LinearGradient({x1: 0, y1: 100, x2: 0, y2: 0});
|
|
7014
7165
|
stops.forEach(d => {
|
|
@@ -9122,7 +9273,7 @@
|
|
|
9122
9273
|
}
|
|
9123
9274
|
|
|
9124
9275
|
if (layout)
|
|
9125
|
-
|
|
9276
|
+
scene.setProperties(c.firstChild, {layout: layout});
|
|
9126
9277
|
//return results;
|
|
9127
9278
|
}
|
|
9128
9279
|
|
|
@@ -10610,12 +10761,18 @@
|
|
|
10610
10761
|
.attr("width", d => d.width).attr("height", rowGap)
|
|
10611
10762
|
.style("fill", "pink").style("opacity", 0.5)
|
|
10612
10763
|
;
|
|
10613
|
-
let
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
.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)
|
|
10617
10767
|
.attr("stroke", "blue").attr("stroke-width", "1px")
|
|
10618
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");
|
|
10619
10776
|
|
|
10620
10777
|
}
|
|
10621
10778
|
|
|
@@ -10813,6 +10970,8 @@
|
|
|
10813
10970
|
|
|
10814
10971
|
if (this._mapping)
|
|
10815
10972
|
json.mapping = this._mapping;
|
|
10973
|
+
if (this._baseItem)
|
|
10974
|
+
json.baseItem = this._baseItem.id;
|
|
10816
10975
|
return json;
|
|
10817
10976
|
}
|
|
10818
10977
|
|
|
@@ -11824,7 +11983,7 @@
|
|
|
11824
11983
|
return scn;
|
|
11825
11984
|
}
|
|
11826
11985
|
|
|
11827
|
-
_loadScale(s) {
|
|
11986
|
+
_loadScale(s, scn) {
|
|
11828
11987
|
let scale;
|
|
11829
11988
|
// if (s.type === "sequentialColor" && s.scheme) {
|
|
11830
11989
|
if (s.type.indexOf("Color") > 0 && s.scheme) {
|
|
@@ -11842,6 +12001,8 @@
|
|
|
11842
12001
|
scale._mapping = s.mapping;
|
|
11843
12002
|
if ("includeZero" in s)
|
|
11844
12003
|
scale.includeZero = s.includeZero;
|
|
12004
|
+
if ("baseItem" in s)
|
|
12005
|
+
scale._baseItem = scn.getItem(s.baseItem);
|
|
11845
12006
|
this.scales[scale.id] = scale;
|
|
11846
12007
|
//console.log(scale.domain, scale.range);
|
|
11847
12008
|
}
|
|
@@ -24148,9 +24309,13 @@
|
|
|
24148
24309
|
}
|
|
24149
24310
|
|
|
24150
24311
|
function canDivide(compnt) {
|
|
24151
|
-
if ([ItemType.Line, ItemType.Circle, ItemType.Rect, ItemType.Area, ItemType.Ring, ItemType.Pie].indexOf(compnt.type) < 0) {
|
|
24312
|
+
if ([ItemType.Line, ItemType.Circle, ItemType.Rect, ItemType.Area, ItemType.Ring, ItemType.Pie, ItemType.Path].indexOf(compnt.type) < 0) {
|
|
24152
24313
|
return false;
|
|
24153
24314
|
}
|
|
24315
|
+
|
|
24316
|
+
if (compnt.type === ItemType.Path && (compnt.closed || !compnt.firstVertex.dataScope))
|
|
24317
|
+
return false;
|
|
24318
|
+
|
|
24154
24319
|
if (!compnt.dataScope) {
|
|
24155
24320
|
return true;
|
|
24156
24321
|
} else {
|
|
@@ -24169,8 +24334,7 @@
|
|
|
24169
24334
|
}
|
|
24170
24335
|
if (!compnt.dataScope) {
|
|
24171
24336
|
return true;
|
|
24172
|
-
}
|
|
24173
|
-
else {
|
|
24337
|
+
} else {
|
|
24174
24338
|
let peers = getPeers(compnt, compnt.getScene());
|
|
24175
24339
|
for (let p of peers) {
|
|
24176
24340
|
if (p.dataScope.numTuples > 1)
|
|
@@ -24180,6 +24344,14 @@
|
|
|
24180
24344
|
}
|
|
24181
24345
|
}
|
|
24182
24346
|
|
|
24347
|
+
function canFormGlyph(args) {
|
|
24348
|
+
for (let itm of args) {
|
|
24349
|
+
if (!isMark(itm))
|
|
24350
|
+
return false;
|
|
24351
|
+
}
|
|
24352
|
+
return true;
|
|
24353
|
+
}
|
|
24354
|
+
|
|
24183
24355
|
function canClassify(item) {
|
|
24184
24356
|
if (item.type !== ItemType.Collection) return false;
|
|
24185
24357
|
if (item.children.length < 2) return false;
|
|
@@ -24205,6 +24377,7 @@
|
|
|
24205
24377
|
exports.canClassify = canClassify;
|
|
24206
24378
|
exports.canDensify = canDensify;
|
|
24207
24379
|
exports.canDivide = canDivide;
|
|
24380
|
+
exports.canFormGlyph = canFormGlyph;
|
|
24208
24381
|
exports.canRepeat = canRepeat;
|
|
24209
24382
|
exports.cartesianToPolar = cartesianToPolar;
|
|
24210
24383
|
exports.createScale = createScale;
|