plotly.js 2.13.1 → 2.14.0

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/lib/locales/nl.js CHANGED
@@ -3,7 +3,41 @@
3
3
  module.exports = {
4
4
  moduleType: 'locale',
5
5
  name: 'nl',
6
- dictionary: {},
6
+ dictionary: {
7
+ 'Autoscale': 'Automatische schaal',
8
+ 'Click to enter Colorscale title': 'Klik om kleurenschaal titel in te vullen',
9
+ 'Click to enter Component A title': 'Klik om Component A titel in te vullen',
10
+ 'Click to enter Component B title': 'Klik om Component B titel in te vullen',
11
+ 'Click to enter Component C title': 'Klik om Component C titel in te vullen',
12
+ 'Click to enter Plot title': 'Klik om Plot titel in te vullen',
13
+ 'Click to enter X axis title': 'Klik om x-as titel in te vullen',
14
+ 'Click to enter Y axis title': 'Klik om y-as titel in te vullen',
15
+ 'Click to enter radial axis title': 'Klik om radiaal-as titel in te vullen',
16
+ 'Double-click to zoom back out': 'Zoom uit door te dubbel klikken',
17
+ 'Download plot as a png': 'Dowload de plot als een png-bestand',
18
+ 'Download plot': 'Download de plot',
19
+ 'Draw circle': 'Teken cirkel',
20
+ 'Draw closed freeform': 'Teken gesloten vorm',
21
+ 'Draw line': 'Teken lijn',
22
+ 'Draw open freeform': 'Teken open vorm',
23
+ 'Draw rectangle': 'Teken rechthoek',
24
+ 'Edit in Chart Studio': 'In Chart Studio wijzigen',
25
+ 'Erase active shape': 'Wis huidige vorm',
26
+ 'IE only supports svg. Changing format to svg.': 'IE ondersteunt alleen svg bestanden. Formaat gewijzigd naar svg.',
27
+ 'Lasso Select': 'Lasso selectie',
28
+ 'Produced with Plotly.js': 'Gemaakt met Plotly.js',
29
+ 'Zoom': 'Inzoomen',
30
+ 'max:': 'maximum:',
31
+ 'mean ± σ:': 'gemiddelde ± σ:',
32
+ 'mean:': 'gemiddelde:',
33
+ 'min:': 'minimum:',
34
+ 'new text': 'nieuwe tekst',
35
+ 'open:': 'openen:',
36
+ 'high:': 'hoog:',
37
+ 'low:': 'laag:',
38
+ 'source:': 'bron:',
39
+ 'target:': 'doel:',
40
+ },
7
41
  format: {
8
42
  days: [
9
43
  'zondag', 'maandag', 'dinsdag', 'woensdag',
@@ -18,6 +52,12 @@ module.exports = {
18
52
  'jan', 'feb', 'maa', 'apr', 'mei', 'jun',
19
53
  'jul', 'aug', 'sep', 'okt', 'nov', 'dec'
20
54
  ],
21
- date: '%d-%m-%Y'
55
+ date: '%d-%m-%Y',
56
+ decimal: ',',
57
+ thousands: '.',
58
+ year: '%Y',
59
+ month: '%b %Y',
60
+ dayMonth: '%-d %b',
61
+ dayMonthYear: '%-d %b %Y'
22
62
  }
23
63
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plotly.js",
3
- "version": "2.13.1",
3
+ "version": "2.14.0",
4
4
  "description": "The open source javascript graphing library that powers plotly",
5
5
  "license": "MIT",
6
6
  "main": "./lib/index.js",
@@ -46,6 +46,10 @@ function draw(gd) {
46
46
  }
47
47
  }
48
48
 
49
+ function couldHaveActiveSelection(gd) {
50
+ return gd._context.editSelection;
51
+ }
52
+
49
53
  function drawOne(gd, index) {
50
54
  // remove the existing selection if there is one.
51
55
  // because indices can change, we need to look in all selection layers
@@ -82,7 +86,7 @@ function drawOne(gd, index) {
82
86
  lineDash = 'solid';
83
87
  }
84
88
 
85
- var isActiveSelection =
89
+ var isActiveSelection = couldHaveActiveSelection(gd) &&
86
90
  gd._fullLayout._activeSelectionIndex === index;
87
91
 
88
92
  if(isActiveSelection) {
@@ -149,6 +153,8 @@ function setClipPath(selectionPath, gd, selectionOptions) {
149
153
 
150
154
 
151
155
  function activateSelection(gd, path) {
156
+ if(!couldHaveActiveSelection(gd)) return;
157
+
152
158
  var element = path.node();
153
159
  var id = +element.getAttribute('data-index');
154
160
  if(id >= 0) {
@@ -165,6 +171,8 @@ function activateSelection(gd, path) {
165
171
  }
166
172
 
167
173
  function activateLastSelection(gd) {
174
+ if(!couldHaveActiveSelection(gd)) return;
175
+
168
176
  var id = gd._fullLayout.selections.length - 1;
169
177
  gd._fullLayout._activeSelectionIndex = id;
170
178
  gd._fullLayout._deactivateSelection = deactivateSelection;
@@ -172,6 +180,8 @@ function activateLastSelection(gd) {
172
180
  }
173
181
 
174
182
  function deactivateSelection(gd) {
183
+ if(!couldHaveActiveSelection(gd)) return;
184
+
175
185
  var id = gd._fullLayout._activeSelectionIndex;
176
186
  if(id >= 0) {
177
187
  clearOutlineControllers(gd);
@@ -50,7 +50,14 @@ var p2r = helpers.p2r;
50
50
  var axValue = helpers.axValue;
51
51
  var getTransform = helpers.getTransform;
52
52
 
53
+ function hasSubplot(dragOptions) {
54
+ // N.B. subplot may be falsy e.g zero sankey index!
55
+ return dragOptions.subplot !== undefined;
56
+ }
57
+
53
58
  function prepSelect(evt, startX, startY, dragOptions, mode) {
59
+ var isCartesian = !hasSubplot(dragOptions);
60
+
54
61
  var isFreeMode = freeMode(mode);
55
62
  var isRectMode = rectMode(mode);
56
63
  var isOpenMode = openMode(mode);
@@ -64,7 +71,7 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
64
71
  var gd = dragOptions.gd;
65
72
  var fullLayout = gd._fullLayout;
66
73
  var immediateSelect = isSelectMode && fullLayout.newselection.mode === 'immediate' &&
67
- !dragOptions.subplot; // N.B. only cartesian subplots have persistent selection
74
+ isCartesian; // N.B. only cartesian subplots have persistent selection
68
75
 
69
76
  var zoomLayer = fullLayout._zoomlayer;
70
77
  var dragBBox = dragOptions.element.getBoundingClientRect();
@@ -112,9 +119,9 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
112
119
  opacity: isDrawMode ? newStyle.opacity / 2 : 1,
113
120
  fill: (isDrawMode && !isOpenMode) ? newStyle.fillcolor : 'none',
114
121
  stroke: newStyle.line.color || (
115
- dragOptions.subplot !== undefined ?
116
- '#7f7f7f' : // non-cartesian subplot
117
- Color.contrast(gd._fullLayout.plot_bgcolor) // cartesian subplot
122
+ isCartesian ?
123
+ Color.contrast(gd._fullLayout.plot_bgcolor) :
124
+ '#7f7f7f' // non-cartesian subplot
118
125
  ),
119
126
  'stroke-dasharray': dashStyle(newStyle.line.dash, newStyle.line.width),
120
127
  'stroke-width': newStyle.line.width + 'px',
@@ -145,6 +152,8 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
145
152
 
146
153
  if(immediateSelect && !evt.shiftKey) {
147
154
  dragOptions._clearSubplotSelections = function() {
155
+ if(!isCartesian) return;
156
+
148
157
  var xRef = xAxis._id;
149
158
  var yRef = yAxis._id;
150
159
  deselectSubplot(gd, xRef, yRef, searchTraces);
@@ -165,6 +174,8 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
165
174
  }
166
175
 
167
176
  if(selectionErased) {
177
+ gd._fullLayout._noEmitSelectedAtStart = true;
178
+
168
179
  Registry.call('_guiRelayout', gd, {
169
180
  selections: list
170
181
  });
@@ -306,10 +317,10 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
306
317
  displayOutlines(convertPoly(mergedPolygons, isOpenMode), outlines, dragOptions);
307
318
 
308
319
  if(isSelectMode) {
309
- var _res = reselect(gd);
320
+ var _res = reselect(gd, false);
310
321
  var extraPoints = _res.eventData ? _res.eventData.points.slice() : [];
311
322
 
312
- _res = reselect(gd, selectionTesters, searchTraces, dragOptions);
323
+ _res = reselect(gd, false, selectionTesters, searchTraces, dragOptions);
313
324
  selectionTesters = _res.selectionTesters;
314
325
  eventData = _res.eventData;
315
326
 
@@ -403,9 +414,13 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
403
414
  }
404
415
  }
405
416
 
406
- Registry.call('_guiRelayout', gd, {
407
- selections: subSelections
408
- });
417
+ if(subSelections.length < allSelections.length) {
418
+ gd._fullLayout._noEmitSelectedAtStart = true;
419
+
420
+ Registry.call('_guiRelayout', gd, {
421
+ selections: subSelections
422
+ });
423
+ }
409
424
  }
410
425
  }
411
426
  } else {
@@ -451,7 +466,9 @@ function prepSelect(evt, startX, startY, dragOptions, mode) {
451
466
  dragOptions.doneFnCompleted(selection);
452
467
  }
453
468
 
454
- emitSelected(gd, eventData);
469
+ if(isSelectMode) {
470
+ emitSelected(gd, eventData);
471
+ }
455
472
  }).catch(Lib.error);
456
473
  };
457
474
  }
@@ -673,15 +690,23 @@ function coerceSelectionsCache(evt, gd, dragOptions) {
673
690
  }
674
691
  }
675
692
 
693
+ function hasActiveShape(gd) {
694
+ return gd._fullLayout._activeShapeIndex >= 0;
695
+ }
696
+
697
+ function hasActiveSelection(gd) {
698
+ return gd._fullLayout._activeSelectionIndex >= 0;
699
+ }
700
+
676
701
  function clearSelectionsCache(dragOptions, immediateSelect) {
677
702
  var dragmode = dragOptions.dragmode;
678
703
  var plotinfo = dragOptions.plotinfo;
679
704
 
680
705
  var gd = dragOptions.gd;
681
- if(gd._fullLayout._activeShapeIndex >= 0) {
706
+ if(hasActiveShape(gd)) {
682
707
  gd._fullLayout._deactivateShape(gd);
683
708
  }
684
- if(gd._fullLayout._activeSelectionIndex >= 0) {
709
+ if(hasActiveSelection(gd)) {
685
710
  gd._fullLayout._deactivateSelection(gd);
686
711
  }
687
712
 
@@ -709,11 +734,13 @@ function clearSelectionsCache(dragOptions, immediateSelect) {
709
734
  var selections;
710
735
  if(
711
736
  isSelectMode &&
712
- !dragOptions.subplot // only allow cartesian - no mapbox for now
737
+ !hasSubplot(dragOptions) // only allow cartesian - no mapbox for now
713
738
  ) {
714
739
  selections = newSelections(outlines, dragOptions);
715
740
  }
716
741
  if(selections) {
742
+ gd._fullLayout._noEmitSelectedAtStart = true;
743
+
717
744
  Registry.call('_guiRelayout', gd, {
718
745
  selections: selections
719
746
  }).then(function() {
@@ -748,7 +775,10 @@ function determineSearchTraces(gd, xAxes, yAxes, subplot) {
748
775
 
749
776
  if(trace.visible !== true || !trace._module || !trace._module.selectPoints) continue;
750
777
 
751
- if(subplot && (trace.subplot === subplot || trace.geo === subplot)) {
778
+ if(
779
+ hasSubplot({subplot: subplot}) &&
780
+ (trace.subplot === subplot || trace.geo === subplot)
781
+ ) {
752
782
  searchTraces.push(createSearchInfo(trace._module, cd, xAxes[0], yAxes[0]));
753
783
  } else if(trace.type === 'splom') {
754
784
  // FIXME: make sure we don't have more than single axis for splom
@@ -1048,7 +1078,7 @@ function _doSelect(selectionTesters, searchTraces) {
1048
1078
  return allSelections;
1049
1079
  }
1050
1080
 
1051
- function reselect(gd, selectionTesters, searchTraces, dragOptions) {
1081
+ function reselect(gd, mayEmitSelected, selectionTesters, searchTraces, dragOptions) {
1052
1082
  var hadSearchTraces = !!searchTraces;
1053
1083
  var plotinfo, xRef, yRef;
1054
1084
  if(dragOptions) {
@@ -1171,15 +1201,15 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
1171
1201
  updateSelectedState(gd, allSearchTraces, eventData);
1172
1202
 
1173
1203
  var clickmode = fullLayout.clickmode;
1174
- var sendEvents = clickmode.indexOf('event') > -1;
1204
+ var sendEvents = clickmode.indexOf('event') > -1 && mayEmitSelected;
1175
1205
 
1176
1206
  if(
1177
1207
  !plotinfo && // get called from plot_api & plots
1178
- fullLayout._reselect
1208
+ mayEmitSelected
1179
1209
  ) {
1180
- if(sendEvents) {
1181
- var activePolygons = getLayoutPolygons(gd, true);
1210
+ var activePolygons = getLayoutPolygons(gd, true);
1182
1211
 
1212
+ if(activePolygons.length) {
1183
1213
  var xref = activePolygons[0].xref;
1184
1214
  var yref = activePolygons[0].yref;
1185
1215
  if(xref && yref) {
@@ -1192,8 +1222,12 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
1192
1222
 
1193
1223
  fillRangeItems(eventData, poly);
1194
1224
  }
1225
+ }
1195
1226
 
1196
- emitSelected(gd, eventData);
1227
+ if(gd._fullLayout._noEmitSelectedAtStart) {
1228
+ gd._fullLayout._noEmitSelectedAtStart = false;
1229
+ } else {
1230
+ if(sendEvents) emitSelected(gd, eventData);
1197
1231
  }
1198
1232
 
1199
1233
  fullLayout._reselect = false;
@@ -1215,7 +1249,7 @@ function reselect(gd, selectionTesters, searchTraces, dragOptions) {
1215
1249
  if(eventData.points.length) {
1216
1250
  emitSelected(gd, eventData);
1217
1251
  } else {
1218
- gd.emit('plotly_deselect', null);
1252
+ emitDeselect(gd);
1219
1253
  }
1220
1254
  }
1221
1255
 
@@ -1503,13 +1537,10 @@ function getFillRangeItems(dragOptions) {
1503
1537
  }
1504
1538
 
1505
1539
  function emitSelecting(gd, eventData) {
1506
- if(drawMode(gd._fullLayout.dragmode)) return;
1507
1540
  gd.emit('plotly_selecting', eventData);
1508
1541
  }
1509
1542
 
1510
1543
  function emitSelected(gd, eventData) {
1511
- if(drawMode(gd._fullLayout.dragmode)) return;
1512
-
1513
1544
  if(eventData) {
1514
1545
  eventData.selections = (gd.layout || {}).selections || [];
1515
1546
  }
@@ -1518,7 +1549,6 @@ function emitSelected(gd, eventData) {
1518
1549
  }
1519
1550
 
1520
1551
  function emitDeselect(gd) {
1521
- if(drawMode(gd._fullLayout.dragmode)) return;
1522
1552
  gd.emit('plotly_deselect', null);
1523
1553
  }
1524
1554
 
@@ -114,6 +114,12 @@ var configAttributes = {
114
114
  }
115
115
  },
116
116
 
117
+ editSelection: {
118
+ valType: 'boolean',
119
+ dflt: true,
120
+ description: 'Enables moving selections.'
121
+ },
122
+
117
123
  autosizable: {
118
124
  valType: 'boolean',
119
125
  dflt: false,
@@ -3364,7 +3364,16 @@ plots.redrag = function(gd) {
3364
3364
  };
3365
3365
 
3366
3366
  plots.reselect = function(gd) {
3367
- Registry.getComponentMethod('selections', 'reselect')(gd);
3367
+ var fullLayout = gd._fullLayout;
3368
+
3369
+ var A = (gd.layout || {}).selections;
3370
+ var B = fullLayout._previousSelections;
3371
+ fullLayout._previousSelections = A;
3372
+
3373
+ var mayEmitSelected = fullLayout._reselect ||
3374
+ JSON.stringify(A) !== JSON.stringify(B);
3375
+
3376
+ Registry.getComponentMethod('selections', 'reselect')(gd, mayEmitSelected);
3368
3377
  };
3369
3378
 
3370
3379
  plots.generalUpdatePerTraceModule = function(gd, subplot, subplotCalcData, subplotLayout) {
@@ -168,6 +168,14 @@ var attrs = module.exports = overrideAll({
168
168
  },
169
169
 
170
170
  link: {
171
+ arrowlen: {
172
+ valType: 'number',
173
+ min: 0,
174
+ dflt: 0,
175
+ description: [
176
+ 'Sets the length (in px) of the links arrow, if 0 no arrow will be drawn.'
177
+ ].join(' ')
178
+ },
171
179
  label: {
172
180
  valType: 'data_array',
173
181
  dflt: [],
@@ -48,6 +48,7 @@ function subplotUpdateFx(gd, index) {
48
48
  var dragMode = fullLayout.dragmode;
49
49
  var cursor = fullLayout.dragmode === 'pan' ? 'move' : 'crosshair';
50
50
  var bgRect = trace._bgRect;
51
+ if(!bgRect) return;
51
52
 
52
53
  if(dragMode === 'pan' || dragMode === 'zoom') return;
53
54
 
@@ -52,6 +52,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
52
52
  return Lib.coerce(linkIn, linkOut, attributes.link, attr, dflt);
53
53
  }
54
54
  coerceLink('label');
55
+ coerceLink('arrowlen');
55
56
  coerceLink('source');
56
57
  coerceLink('target');
57
58
  coerceLink('value');
@@ -271,6 +271,7 @@ function sankeyModel(layout, d, traceIndex) {
271
271
  nodeLineWidth: trace.node.line.width,
272
272
  linkLineColor: trace.link.line.color,
273
273
  linkLineWidth: trace.link.line.width,
274
+ linkArrowLength: trace.link.arrowlen,
274
275
  valueFormat: trace.valueformat,
275
276
  valueSuffix: trace.valuesuffix,
276
277
  textFont: trace.textfont,
@@ -309,6 +310,7 @@ function linkModel(d, l, i) {
309
310
  linkPath: linkPath,
310
311
  linkLineColor: d.linkLineColor,
311
312
  linkLineWidth: d.linkLineWidth,
313
+ linkArrowLength: d.linkArrowLength,
312
314
  valueFormat: d.valueFormat,
313
315
  valueSuffix: d.valueSuffix,
314
316
  sankey: d.sankey,
@@ -318,7 +320,7 @@ function linkModel(d, l, i) {
318
320
  };
319
321
  }
320
322
 
321
- function createCircularClosedPathString(link) {
323
+ function createCircularClosedPathString(link, arrowLen) {
322
324
  // Using coordinates computed by d3-sankey-circular
323
325
  var pathString = '';
324
326
  var offset = link.width / 2;
@@ -328,17 +330,17 @@ function createCircularClosedPathString(link) {
328
330
  pathString =
329
331
  // start at the left of the target node
330
332
  'M ' +
331
- coords.targetX + ' ' + (coords.targetY + offset) + ' ' +
333
+ (coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) + ' ' +
332
334
  'L' +
333
- coords.rightInnerExtent + ' ' + (coords.targetY + offset) +
335
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) +
334
336
  'A' +
335
337
  (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 1 ' +
336
- (coords.rightFullExtent - offset) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
338
+ (coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
337
339
  'L' +
338
- (coords.rightFullExtent - offset) + ' ' + coords.verticalRightInnerExtent +
340
+ (coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
339
341
  'A' +
340
342
  (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 1 ' +
341
- coords.rightInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
343
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) +
342
344
  'L' +
343
345
  coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
344
346
  'A' +
@@ -366,34 +368,35 @@ function createCircularClosedPathString(link) {
366
368
  (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 0 ' +
367
369
  coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
368
370
  'L' +
369
- coords.rightInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
371
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) +
370
372
  'A' +
371
373
  (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 0 ' +
372
- (coords.rightFullExtent + offset) + ' ' + coords.verticalRightInnerExtent +
374
+ (coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
373
375
  'L' +
374
- (coords.rightFullExtent + offset) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
376
+ (coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
375
377
  'A' +
376
378
  (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 0 ' +
377
- coords.rightInnerExtent + ' ' + (coords.targetY - offset) +
379
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) +
378
380
  'L' +
379
- coords.targetX + ' ' + (coords.targetY - offset) +
381
+ (coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) +
382
+ (arrowLen > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
380
383
  'Z';
381
384
  } else {
382
385
  // Bottom path
383
386
  pathString =
384
387
  // start at the left of the target node
385
388
  'M ' +
386
- coords.targetX + ' ' + (coords.targetY - offset) + ' ' +
389
+ (coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) + ' ' +
387
390
  'L' +
388
- coords.rightInnerExtent + ' ' + (coords.targetY - offset) +
391
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) +
389
392
  'A' +
390
393
  (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 0 ' +
391
- (coords.rightFullExtent - offset) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
394
+ (coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
392
395
  'L' +
393
- (coords.rightFullExtent - offset) + ' ' + coords.verticalRightInnerExtent +
396
+ (coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
394
397
  'A' +
395
398
  (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 0 ' +
396
- coords.rightInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
399
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) +
397
400
  'L' +
398
401
  coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
399
402
  'A' +
@@ -421,17 +424,18 @@ function createCircularClosedPathString(link) {
421
424
  (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 1 ' +
422
425
  coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
423
426
  'L' +
424
- coords.rightInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
427
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) +
425
428
  'A' +
426
429
  (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 1 ' +
427
- (coords.rightFullExtent + offset) + ' ' + coords.verticalRightInnerExtent +
430
+ (coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
428
431
  'L' +
429
- (coords.rightFullExtent + offset) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
432
+ (coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
430
433
  'A' +
431
434
  (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 1 ' +
432
- coords.rightInnerExtent + ' ' + (coords.targetY + offset) +
435
+ (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) +
433
436
  'L' +
434
- coords.targetX + ' ' + (coords.targetY + offset) +
437
+ (coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) +
438
+ (arrowLen > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
435
439
  'Z';
436
440
  }
437
441
  return pathString;
@@ -440,11 +444,16 @@ function createCircularClosedPathString(link) {
440
444
  function linkPath() {
441
445
  var curvature = 0.5;
442
446
  function path(d) {
447
+ var arrowLen = d.linkArrowLength;
443
448
  if(d.link.circular) {
444
- return createCircularClosedPathString(d.link);
449
+ return createCircularClosedPathString(d.link, arrowLen);
445
450
  } else {
451
+ var maxArrowLength = Math.abs((d.link.target.x0 - d.link.source.x1) / 2);
452
+ if(arrowLen > maxArrowLength) {
453
+ arrowLen = maxArrowLength;
454
+ }
446
455
  var x0 = d.link.source.x1;
447
- var x1 = d.link.target.x0;
456
+ var x1 = d.link.target.x0 - arrowLen;
448
457
  var xi = interpolateNumber(x0, x1);
449
458
  var x2 = xi(curvature);
450
459
  var x3 = xi(1 - curvature);
@@ -452,15 +461,17 @@ function linkPath() {
452
461
  var y0b = d.link.y0 + d.link.width / 2;
453
462
  var y1a = d.link.y1 - d.link.width / 2;
454
463
  var y1b = d.link.y1 + d.link.width / 2;
455
- return 'M' + x0 + ',' + y0a +
456
- 'C' + x2 + ',' + y0a +
457
- ' ' + x3 + ',' + y1a +
458
- ' ' + x1 + ',' + y1a +
459
- 'L' + x1 + ',' + y1b +
460
- 'C' + x3 + ',' + y1b +
461
- ' ' + x2 + ',' + y0b +
462
- ' ' + x0 + ',' + y0b +
463
- 'Z';
464
+ var start = 'M' + x0 + ',' + y0a;
465
+ var upperCurve = 'C' + x2 + ',' + y0a +
466
+ ' ' + x3 + ',' + y1a +
467
+ ' ' + x1 + ',' + y1a;
468
+ var lowerCurve = 'C' + x3 + ',' + y1b +
469
+ ' ' + x2 + ',' + y0b +
470
+ ' ' + x0 + ',' + y0b;
471
+
472
+ var rightEnd = arrowLen > 0 ? 'L' + (x1 + arrowLen) + ',' + (y1a + d.link.width / 2) : '';
473
+ rightEnd += 'L' + x1 + ',' + y1b;
474
+ return start + upperCurve + rightEnd + lowerCurve + 'Z';
464
475
  }
465
476
  }
466
477
  return path;
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use strict';
2
2
 
3
3
  // package version injected by `npm run preprocess`
4
- exports.version = '2.13.1';
4
+ exports.version = '2.14.0';