plotly.js 2.6.1 → 2.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plotly.js",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "The open source javascript graphing library that powers plotly",
5
5
  "license": "MIT",
6
6
  "main": "./lib/index.js",
@@ -103,7 +103,7 @@
103
103
  "native-promise-only": "^0.8.1",
104
104
  "parse-svg-path": "^0.1.2",
105
105
  "polybooljs": "^1.2.0",
106
- "probe-image-size": "^7.2.1",
106
+ "probe-image-size": "^7.2.2",
107
107
  "regl": "^2.1.0",
108
108
  "regl-error2d": "^2.0.12",
109
109
  "regl-line2d": "^3.1.2",
@@ -113,6 +113,7 @@
113
113
  "superscript-text": "^1.0.0",
114
114
  "svg-path-sdf": "^1.1.3",
115
115
  "tinycolor2": "^1.4.2",
116
+ "to-px": "1.0.1",
116
117
  "topojson-client": "^3.1.0",
117
118
  "webgl-context": "^2.2.0",
118
119
  "world-calendars": "^1.0.3"
@@ -124,12 +125,12 @@
124
125
  "browserify-transform-tools": "^1.7.0",
125
126
  "bubleify": "^2.0.0",
126
127
  "canvas": "^2.8.0",
127
- "check-node-version": "^4.1.0",
128
+ "check-node-version": "^4.2.1",
128
129
  "chttps": "^1.0.6",
129
130
  "deep-equal": "^2.0.5",
130
131
  "derequire": "^2.1.1",
131
132
  "ecstatic": "^4.1.4",
132
- "eslint": "^8.1.0",
133
+ "eslint": "^8.3.0",
133
134
  "extra-iterable": "^2.5.22",
134
135
  "falafel": "^2.2.4",
135
136
  "fs-extra": "^10.0.0",
@@ -138,11 +139,11 @@
138
139
  "gzip-size": "^6.0.0",
139
140
  "into-stream": "^6.0.0",
140
141
  "jasmine-core": "^3.5.0",
141
- "jsdom": "^18.0.0",
142
- "karma": "^6.3.6",
142
+ "jsdom": "^18.1.1",
143
+ "karma": "^6.3.9",
143
144
  "karma-browserify": "^8.1.0",
144
145
  "karma-chrome-launcher": "^3.1.0",
145
- "karma-firefox-launcher": "^2.1.1",
146
+ "karma-firefox-launcher": "^2.1.2",
146
147
  "karma-ie-launcher": "^1.0.0",
147
148
  "karma-jasmine": "^3.3.1",
148
149
  "karma-jasmine-spec-tags": "^1.3.0",
@@ -154,14 +155,14 @@
154
155
  "mathjax": "2.7.5",
155
156
  "minify-stream": "^2.1.0",
156
157
  "npm-link-check": "^4.0.0",
157
- "open": "^8.3.0",
158
+ "open": "^8.4.0",
158
159
  "pixelmatch": "^5.2.1",
159
160
  "prepend-file": "^2.0.0",
160
161
  "prettysize": "^2.0.0",
161
162
  "read-last-lines": "^1.8.0",
162
163
  "run-series": "^1.1.9",
163
164
  "sane-topojson": "^4.0.0",
164
- "sass": "^1.42.1",
165
+ "sass": "^1.43.4",
165
166
  "through2": "^4.0.2",
166
167
  "true-case-path": "^2.2.1",
167
168
  "watchify": "^4.0.0"
@@ -167,6 +167,19 @@ function makeColorBarData(gd) {
167
167
  }
168
168
 
169
169
  function drawColorBar(g, opts, gd) {
170
+ var len = opts.len;
171
+ var lenmode = opts.lenmode;
172
+ var thickness = opts.thickness;
173
+ var thicknessmode = opts.thicknessmode;
174
+ var outlinewidth = opts.outlinewidth;
175
+ var borderwidth = opts.borderwidth;
176
+ var xanchor = opts.xanchor;
177
+ var yanchor = opts.yanchor;
178
+ var xpad = opts.xpad;
179
+ var ypad = opts.ypad;
180
+ var optsX = opts.x;
181
+ var optsY = opts.y;
182
+
170
183
  var fullLayout = gd._fullLayout;
171
184
  var gs = fullLayout._size;
172
185
 
@@ -196,42 +209,41 @@ function drawColorBar(g, opts, gd) {
196
209
  // when the colorbar itself is pushing the margins.
197
210
  // but then the fractional size is calculated based on the
198
211
  // actual graph size, so that the axes will size correctly.
199
- var thickPx = Math.round(opts.thickness * (opts.thicknessmode === 'fraction' ? gs.w : 1));
212
+ var thickPx = Math.round(thickness * (thicknessmode === 'fraction' ? gs.w : 1));
200
213
  var thickFrac = thickPx / gs.w;
201
- var lenPx = Math.round(opts.len * (opts.lenmode === 'fraction' ? gs.h : 1));
214
+ var lenPx = Math.round(len * (lenmode === 'fraction' ? gs.h : 1));
202
215
  var lenFrac = lenPx / gs.h;
203
- var xpadFrac = opts.xpad / gs.w;
204
- var yExtraPx = (opts.borderwidth + opts.outlinewidth) / 2;
205
- var ypadFrac = opts.ypad / gs.h;
216
+ var xpadFrac = xpad / gs.w;
217
+ var yExtraPx = (borderwidth + outlinewidth) / 2;
218
+ var ypadFrac = ypad / gs.h;
206
219
 
207
220
  // x positioning: do it initially just for left anchor,
208
221
  // then fix at the end (since we don't know the width yet)
209
- var xLeft = Math.round(opts.x * gs.w + opts.xpad);
222
+ var uPx = Math.round(optsX * gs.w + xpad);
210
223
  // for dragging... this is getting a little muddled...
211
- var xLeftFrac = opts.x - thickFrac * ({center: 0.5, right: 1}[opts.xanchor] || 0);
224
+ var uFrac = optsX - thickFrac * ({center: 0.5, right: 1}[xanchor] || 0);
212
225
 
213
226
  // y positioning we can do correctly from the start
214
- var yBottomFrac = opts.y + lenFrac * (({top: -0.5, bottom: 0.5}[opts.yanchor] || 0) - 0.5);
215
- var yBottomPx = Math.round(gs.h * (1 - yBottomFrac));
216
- var yTopPx = yBottomPx - lenPx;
227
+ var vFrac = optsY + lenFrac * (({top: -0.5, bottom: 0.5}[yanchor] || 0) - 0.5);
228
+ var vPx = Math.round(gs.h * (1 - vFrac));
217
229
 
218
230
  // stash a few things for makeEditable
219
231
  opts._lenFrac = lenFrac;
220
232
  opts._thickFrac = thickFrac;
221
- opts._xLeftFrac = xLeftFrac;
222
- opts._yBottomFrac = yBottomFrac;
233
+ opts._uFrac = uFrac;
234
+ opts._vFrac = vFrac;
223
235
 
224
236
  // stash mocked axis for contour label formatting
225
237
  var ax = opts._axis = mockColorBarAxis(gd, opts, zrange);
226
238
 
227
239
  // position can't go in through supplyDefaults
228
240
  // because that restricts it to [0,1]
229
- ax.position = opts.x + xpadFrac + thickFrac;
241
+ ax.position = optsX + xpadFrac + thickFrac;
230
242
 
231
243
  if(['top', 'bottom'].indexOf(titleSide) !== -1) {
232
244
  ax.title.side = titleSide;
233
- ax.titlex = opts.x + xpadFrac;
234
- ax.titley = yBottomFrac + (title.side === 'top' ? lenFrac - ypadFrac : ypadFrac);
245
+ ax.titlex = optsX + xpadFrac;
246
+ ax.titley = vFrac + (title.side === 'top' ? lenFrac - ypadFrac : ypadFrac);
235
247
  }
236
248
 
237
249
  if(line.color && opts.tickmode === 'auto') {
@@ -239,7 +251,7 @@ function drawColorBar(g, opts, gd) {
239
251
  ax.tick0 = levelsIn.start;
240
252
  var dtick = levelsIn.size;
241
253
  // expand if too many contours, so we don't get too many ticks
242
- var autoNtick = Lib.constrain((yBottomPx - yTopPx) / 50, 4, 15) + 1;
254
+ var autoNtick = Lib.constrain(lenPx / 50, 4, 15) + 1;
243
255
  var dtFactor = (zrange[1] - zrange[0]) / ((opts.nticks || autoNtick) * dtick);
244
256
  if(dtFactor > 1) {
245
257
  var dtexp = Math.pow(10, Math.floor(Math.log(dtFactor) / Math.LN10));
@@ -257,8 +269,8 @@ function drawColorBar(g, opts, gd) {
257
269
  // set domain after init, because we may want to
258
270
  // allow it outside [0,1]
259
271
  ax.domain = [
260
- yBottomFrac + ypadFrac,
261
- yBottomFrac + lenFrac - ypadFrac
272
+ vFrac + ypadFrac,
273
+ vFrac + lenFrac - ypadFrac
262
274
  ];
263
275
 
264
276
  ax.setScale();
@@ -299,15 +311,15 @@ function drawColorBar(g, opts, gd) {
299
311
  // draw the title so we know how much room it needs
300
312
  // when we squish the axis. This one only applies to
301
313
  // top or bottom titles, not right side.
302
- var x = gs.l + (opts.x + xpadFrac) * gs.w;
314
+ var x = gs.l + (optsX + xpadFrac) * gs.w;
303
315
  var fontSize = ax.title.font.size;
304
316
  var y;
305
317
 
306
318
  if(titleSide === 'top') {
307
- y = (1 - (yBottomFrac + lenFrac - ypadFrac)) * gs.h +
319
+ y = (1 - (vFrac + lenFrac - ypadFrac)) * gs.h +
308
320
  gs.t + 3 + fontSize * 0.75;
309
321
  } else {
310
- y = (1 - (yBottomFrac + ypadFrac)) * gs.h +
322
+ y = (1 - (vFrac + ypadFrac)) * gs.h +
311
323
  gs.t - 3 - fontSize * 0.25;
312
324
  }
313
325
  drawTitle(ax._id + 'title', {
@@ -346,7 +358,7 @@ function drawColorBar(g, opts, gd) {
346
358
  // squish the axis top to make room for the title
347
359
  var titleGroup = g.select('.' + cn.cbtitle);
348
360
  var titleText = titleGroup.select('text');
349
- var titleTrans = [-opts.outlinewidth / 2, opts.outlinewidth / 2];
361
+ var titleTrans = [-outlinewidth / 2, outlinewidth / 2];
350
362
  var mathJaxNode = titleGroup
351
363
  .select('.h' + ax._id + 'title-math-group')
352
364
  .node();
@@ -418,7 +430,7 @@ function drawColorBar(g, opts, gd) {
418
430
  // Colorbar cannot currently support opacities so we
419
431
  // use an opaque fill even when alpha channels present
420
432
  var fillEl = d3.select(this).attr({
421
- x: xLeft,
433
+ x: uPx,
422
434
  width: Math.max(thickPx, 2),
423
435
  y: d3.min(z),
424
436
  height: Math.max(d3.max(z) - d3.min(z), 2),
@@ -442,7 +454,7 @@ function drawColorBar(g, opts, gd) {
442
454
  lines.exit().remove();
443
455
  lines.each(function(d) {
444
456
  d3.select(this)
445
- .attr('d', 'M' + xLeft + ',' +
457
+ .attr('d', 'M' + uPx + ',' +
446
458
  (Math.round(ax.c2p(d)) + (line.width / 2) % 1) + 'h' + thickPx)
447
459
  .call(Drawing.lineGroupStyle, line.width, lineColormap(d), line.dash);
448
460
  });
@@ -450,8 +462,8 @@ function drawColorBar(g, opts, gd) {
450
462
  // force full redraw of labels and ticks
451
463
  axLayer.selectAll('g.' + ax._id + 'tick,path').remove();
452
464
 
453
- var shift = xLeft + thickPx +
454
- (opts.outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
465
+ var shift = uPx + thickPx +
466
+ (outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
455
467
 
456
468
  var vals = Axes.calcTicks(ax);
457
469
  var tickSign = Axes.getTickSigns(ax)[2];
@@ -476,9 +488,9 @@ function drawColorBar(g, opts, gd) {
476
488
  // TODO: why are we redrawing multiple times now with this?
477
489
  // I guess autoMargin doesn't like being post-promise?
478
490
  function positionCB() {
479
- var innerWidth = thickPx + opts.outlinewidth / 2;
491
+ var innerThickness = thickPx + outlinewidth / 2;
480
492
  if(ax.ticklabelposition.indexOf('inside') === -1) {
481
- innerWidth += Drawing.bBox(axLayer.node()).width;
493
+ innerThickness += Drawing.bBox(axLayer.node()).width;
482
494
  }
483
495
 
484
496
  titleEl = titleCont.select('text');
@@ -493,66 +505,65 @@ function drawColorBar(g, opts, gd) {
493
505
  // (except for top/bottom mathjax, above)
494
506
  // but the weird gs.l is because the titleunshift
495
507
  // transform gets removed by Drawing.bBox
496
- titleWidth = Drawing.bBox(titleCont.node()).right - xLeft - gs.l;
508
+ titleWidth = Drawing.bBox(titleCont.node()).right - uPx - gs.l;
497
509
  }
498
- innerWidth = Math.max(innerWidth, titleWidth);
510
+ innerThickness = Math.max(innerThickness, titleWidth);
499
511
  }
500
512
 
501
- var outerwidth = 2 * opts.xpad + innerWidth + opts.borderwidth + opts.outlinewidth / 2;
502
- var outerheight = yBottomPx - yTopPx;
513
+ var outerThickness = 2 * xpad + innerThickness + borderwidth + outlinewidth / 2;
503
514
 
504
515
  g.select('.' + cn.cbbg).attr({
505
- x: xLeft - opts.xpad - (opts.borderwidth + opts.outlinewidth) / 2,
506
- y: yTopPx - yExtraPx,
507
- width: Math.max(outerwidth, 2),
508
- height: Math.max(outerheight + 2 * yExtraPx, 2)
516
+ x: uPx - xpad - (borderwidth + outlinewidth) / 2,
517
+ y: vPx - lenPx - yExtraPx,
518
+ width: Math.max(outerThickness, 2),
519
+ height: Math.max(lenPx + 2 * yExtraPx, 2)
509
520
  })
510
521
  .call(Color.fill, opts.bgcolor)
511
522
  .call(Color.stroke, opts.bordercolor)
512
- .style('stroke-width', opts.borderwidth);
523
+ .style('stroke-width', borderwidth);
513
524
 
514
525
  g.selectAll('.' + cn.cboutline).attr({
515
- x: xLeft,
516
- y: yTopPx + opts.ypad + (titleSide === 'top' ? titleHeight : 0),
526
+ x: uPx,
527
+ y: vPx - lenPx + ypad + (titleSide === 'top' ? titleHeight : 0),
517
528
  width: Math.max(thickPx, 2),
518
- height: Math.max(outerheight - 2 * opts.ypad - titleHeight, 2)
529
+ height: Math.max(lenPx - 2 * ypad - titleHeight, 2)
519
530
  })
520
531
  .call(Color.stroke, opts.outlinecolor)
521
532
  .style({
522
533
  fill: 'none',
523
- 'stroke-width': opts.outlinewidth
534
+ 'stroke-width': outlinewidth
524
535
  });
525
536
 
526
537
  // fix positioning for xanchor!='left'
527
- var xoffset = ({center: 0.5, right: 1}[opts.xanchor] || 0) * outerwidth;
538
+ var xoffset = ({center: 0.5, right: 1}[xanchor] || 0) * outerThickness;
528
539
  g.attr('transform', strTranslate(gs.l - xoffset, gs.t));
529
540
 
530
541
  // auto margin adjustment
531
542
  var marginOpts = {};
532
- var tFrac = FROM_TL[opts.yanchor];
533
- var bFrac = FROM_BR[opts.yanchor];
534
- if(opts.lenmode === 'pixels') {
535
- marginOpts.y = opts.y;
536
- marginOpts.t = outerheight * tFrac;
537
- marginOpts.b = outerheight * bFrac;
543
+ var tFrac = FROM_TL[yanchor];
544
+ var bFrac = FROM_BR[yanchor];
545
+ if(lenmode === 'pixels') {
546
+ marginOpts.y = optsY;
547
+ marginOpts.t = lenPx * tFrac;
548
+ marginOpts.b = lenPx * bFrac;
538
549
  } else {
539
550
  marginOpts.t = marginOpts.b = 0;
540
- marginOpts.yt = opts.y + opts.len * tFrac;
541
- marginOpts.yb = opts.y - opts.len * bFrac;
551
+ marginOpts.yt = optsY + len * tFrac;
552
+ marginOpts.yb = optsY - len * bFrac;
542
553
  }
543
554
 
544
- var lFrac = FROM_TL[opts.xanchor];
545
- var rFrac = FROM_BR[opts.xanchor];
546
- if(opts.thicknessmode === 'pixels') {
547
- marginOpts.x = opts.x;
548
- marginOpts.l = outerwidth * lFrac;
549
- marginOpts.r = outerwidth * rFrac;
555
+ var lFrac = FROM_TL[xanchor];
556
+ var rFrac = FROM_BR[xanchor];
557
+ if(thicknessmode === 'pixels') {
558
+ marginOpts.x = optsX;
559
+ marginOpts.l = outerThickness * lFrac;
560
+ marginOpts.r = outerThickness * rFrac;
550
561
  } else {
551
- var extraThickness = outerwidth - thickPx;
562
+ var extraThickness = outerThickness - thickPx;
552
563
  marginOpts.l = extraThickness * lFrac;
553
564
  marginOpts.r = extraThickness * rFrac;
554
- marginOpts.xl = opts.x - opts.thickness * lFrac;
555
- marginOpts.xr = opts.x + opts.thickness * rFrac;
565
+ marginOpts.xl = optsX - thickness * lFrac;
566
+ marginOpts.xr = optsX + thickness * rFrac;
556
567
  }
557
568
 
558
569
  Plots.autoMargin(gd, opts._id, marginOpts);
@@ -583,9 +594,9 @@ function makeEditable(g, opts, gd) {
583
594
  moveFn: function(dx, dy) {
584
595
  g.attr('transform', t0 + strTranslate(dx, dy));
585
596
 
586
- xf = dragElement.align(opts._xLeftFrac + (dx / gs.w), opts._thickFrac,
597
+ xf = dragElement.align(opts._uFrac + (dx / gs.w), opts._thickFrac,
587
598
  0, 1, opts.xanchor);
588
- yf = dragElement.align(opts._yBottomFrac - (dy / gs.h), opts._lenFrac,
599
+ yf = dragElement.align(opts._vFrac - (dy / gs.h), opts._lenFrac,
589
600
  0, 1, opts.yanchor);
590
601
 
591
602
  var csr = dragElement.getCursor(xf, yf, opts.xanchor, opts.yanchor);
@@ -927,7 +927,7 @@ var TEXTOFFSETSIGN = {
927
927
  start: 1, end: -1, middle: 0, bottom: 1, top: -1
928
928
  };
929
929
 
930
- function textPointPosition(s, textPosition, fontSize, markerRadius) {
930
+ function textPointPosition(s, textPosition, fontSize, markerRadius, dontTouchParent) {
931
931
  var group = d3.select(s.node().parentNode);
932
932
 
933
933
  var v = textPosition.indexOf('top') !== -1 ?
@@ -949,7 +949,9 @@ function textPointPosition(s, textPosition, fontSize, markerRadius) {
949
949
 
950
950
  // fix the overall text group position
951
951
  s.attr('text-anchor', h);
952
- group.attr('transform', strTranslate(dx, dy));
952
+ if(!dontTouchParent) {
953
+ group.attr('transform', strTranslate(dx, dy));
954
+ }
953
955
  }
954
956
 
955
957
  function extracTextFontSize(d, trace) {
@@ -1019,7 +1021,8 @@ drawing.selectedTextStyle = function(s, trace) {
1019
1021
  var fontSize = extracTextFontSize(d, trace);
1020
1022
 
1021
1023
  Color.fill(tx, tc);
1022
- textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc);
1024
+ var dontTouchParent = Registry.traceIs(trace, 'bar-like');
1025
+ textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc, dontTouchParent);
1023
1026
  });
1024
1027
  };
1025
1028
 
@@ -78,11 +78,13 @@ var cartesianScatterPoints = {
78
78
  // The actual rendering is done by private function _hover.
79
79
  exports.hover = function hover(gd, evt, subplot, noHoverEvent) {
80
80
  gd = Lib.getGraphDiv(gd);
81
-
81
+ // The 'target' property changes when bubbling out of Shadow DOM.
82
+ // Throttling can delay reading the target, so we save the current value.
83
+ var eventTarget = evt.target;
82
84
  Lib.throttle(
83
85
  gd._fullLayout._uid + constants.HOVERID,
84
86
  constants.HOVERMINTIME,
85
- function() { _hover(gd, evt, subplot, noHoverEvent); }
87
+ function() { _hover(gd, evt, subplot, noHoverEvent, eventTarget); }
86
88
  );
87
89
  };
88
90
 
@@ -247,7 +249,7 @@ exports.loneHover = function loneHover(hoverItems, opts) {
247
249
  };
248
250
 
249
251
  // The actual implementation is here:
250
- function _hover(gd, evt, subplot, noHoverEvent) {
252
+ function _hover(gd, evt, subplot, noHoverEvent, eventTarget) {
251
253
  if(!subplot) subplot = 'xy';
252
254
 
253
255
  // if the user passed in an array of subplots,
@@ -366,7 +368,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
366
368
  // [x|y]px: the pixels (from top left) of the mouse location
367
369
  // on the currently selected plot area
368
370
  // add pointerX|Y property for drawing the spikes in spikesnap 'cursor' situation
369
- var hasUserCalledHover = !evt.target;
371
+ var hasUserCalledHover = !eventTarget;
370
372
  var xpx, ypx;
371
373
 
372
374
  if(hasUserCalledHover) {
@@ -383,13 +385,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
383
385
  return;
384
386
  }
385
387
 
386
- // Discover event target, traversing open shadow roots.
387
- var target = evt.composedPath && evt.composedPath()[0];
388
- if(!target) {
389
- // Fallback for browsers not supporting composedPath
390
- target = evt.target;
391
- }
392
- var dbb = target.getBoundingClientRect();
388
+ var dbb = eventTarget.getBoundingClientRect();
393
389
 
394
390
  xpx = evt.clientX - dbb.left;
395
391
  ypx = evt.clientY - dbb.top;
@@ -837,15 +833,15 @@ function _hover(gd, evt, subplot, noHoverEvent) {
837
833
  if(!helpers.isUnifiedHover(hovermode)) {
838
834
  hoverAvoidOverlaps(hoverLabels, rotateLabels ? 'xa' : 'ya', fullLayout);
839
835
  alignHoverText(hoverLabels, rotateLabels, fullLayout._invScaleX, fullLayout._invScaleY);
840
- } // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true
836
+ } // TODO: tagName hack is needed to appease geo.js's hack of using eventTarget=true
841
837
  // we should improve the "fx" API so other plots can use it without these hack.
842
- if(evt.target && evt.target.tagName) {
838
+ if(eventTarget && eventTarget.tagName) {
843
839
  var hasClickToShow = Registry.getComponentMethod('annotations', 'hasClickToShow')(gd, newhoverdata);
844
- overrideCursor(d3.select(evt.target), hasClickToShow ? 'pointer' : '');
840
+ overrideCursor(d3.select(eventTarget), hasClickToShow ? 'pointer' : '');
845
841
  }
846
842
 
847
843
  // don't emit events if called manually
848
- if(!evt.target || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
844
+ if(!eventTarget || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
849
845
 
850
846
  if(oldhoverdata) {
851
847
  gd.emit('plotly_unhover', {
@@ -2396,7 +2396,8 @@ function findUIPattern(key, patternSpecs) {
2396
2396
  var spec = patternSpecs[i];
2397
2397
  var match = key.match(spec.pattern);
2398
2398
  if(match) {
2399
- return {head: match[1], attr: spec.attr};
2399
+ var head = match[1] || '';
2400
+ return {head: head, tail: key.substr(head.length + 1), attr: spec.attr};
2400
2401
  }
2401
2402
  }
2402
2403
  }
@@ -2448,26 +2449,54 @@ function valsMatch(v1, v2) {
2448
2449
 
2449
2450
  function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
2450
2451
  var layoutPreGUI = oldFullLayout._preGUI;
2451
- var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal;
2452
+ var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal, head, tail;
2452
2453
  var bothInheritAutorange = [];
2454
+ var newAutorangeIn = {};
2453
2455
  var newRangeAccepted = {};
2454
2456
  for(key in layoutPreGUI) {
2455
2457
  match = findUIPattern(key, layoutUIControlPatterns);
2456
2458
  if(match) {
2457
- revAttr = match.attr || (match.head + '.uirevision');
2459
+ head = match.head;
2460
+ tail = match.tail;
2461
+ revAttr = match.attr || (head + '.uirevision');
2458
2462
  oldRev = nestedProperty(oldFullLayout, revAttr).get();
2459
2463
  newRev = oldRev && getNewRev(revAttr, layout);
2464
+
2460
2465
  if(newRev && (newRev === oldRev)) {
2461
2466
  preGUIVal = layoutPreGUI[key];
2462
2467
  if(preGUIVal === null) preGUIVal = undefined;
2463
2468
  newNP = nestedProperty(layout, key);
2464
2469
  newVal = newNP.get();
2470
+
2465
2471
  if(valsMatch(newVal, preGUIVal)) {
2466
- if(newVal === undefined && key.substr(key.length - 9) === 'autorange') {
2467
- bothInheritAutorange.push(key.substr(0, key.length - 10));
2472
+ if(newVal === undefined && tail === 'autorange') {
2473
+ bothInheritAutorange.push(head);
2468
2474
  }
2469
2475
  newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
2470
2476
  continue;
2477
+ } else if(tail === 'autorange' || tail.substr(0, 6) === 'range[') {
2478
+ // Special case for (auto)range since we push it back into the layout
2479
+ // so all null should be treated equivalently to autorange: true with any range
2480
+ var pre0 = layoutPreGUI[head + '.range[0]'];
2481
+ var pre1 = layoutPreGUI[head + '.range[1]'];
2482
+ var preAuto = layoutPreGUI[head + '.autorange'];
2483
+ if(preAuto || (preAuto === null && pre0 === null && pre1 === null)) {
2484
+ // Only read the input layout once and stash the result,
2485
+ // so we get it before we start modifying it
2486
+ if(!(head in newAutorangeIn)) {
2487
+ var newContainer = nestedProperty(layout, head).get();
2488
+ newAutorangeIn[head] = newContainer && (
2489
+ newContainer.autorange ||
2490
+ (newContainer.autorange !== false && (
2491
+ !newContainer.range || newContainer.range.length !== 2)
2492
+ )
2493
+ );
2494
+ }
2495
+ if(newAutorangeIn[head]) {
2496
+ newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
2497
+ continue;
2498
+ }
2499
+ }
2471
2500
  }
2472
2501
  }
2473
2502
  } else {
@@ -2478,12 +2507,12 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
2478
2507
  // so remove it from _preGUI for next time.
2479
2508
  delete layoutPreGUI[key];
2480
2509
 
2481
- if(key.substr(key.length - 8, 6) === 'range[') {
2482
- newRangeAccepted[key.substr(0, key.length - 9)] = 1;
2510
+ if(match && match.tail.substr(0, 6) === 'range[') {
2511
+ newRangeAccepted[match.head] = 1;
2483
2512
  }
2484
2513
  }
2485
2514
 
2486
- // Special logic for `autorange`, since it interacts with `range`:
2515
+ // More special logic for `autorange`, since it interacts with `range`:
2487
2516
  // If the new figure's matching `range` was kept, and `autorange`
2488
2517
  // wasn't supplied explicitly in either the original or the new figure,
2489
2518
  // we shouldn't alter that - but we may just have done that, so fix it.
@@ -722,11 +722,14 @@ proto.project = function(v) {
722
722
  proto.getView = function() {
723
723
  var map = this.map;
724
724
  var mapCenter = map.getCenter();
725
- var center = { lon: mapCenter.lng, lat: mapCenter.lat };
725
+ var lon = mapCenter.lng;
726
+ var lat = mapCenter.lat;
727
+ var center = { lon: lon, lat: lat };
726
728
 
727
729
  var canvas = map.getCanvas();
728
- var w = canvas.width;
729
- var h = canvas.height;
730
+ var w = parseInt(canvas.style.width);
731
+ var h = parseInt(canvas.style.height);
732
+
730
733
  return {
731
734
  center: center,
732
735
  zoom: map.getZoom(),
@@ -428,7 +428,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
428
428
  }
429
429
 
430
430
  transform.fontSize = font.size;
431
- recordMinTextSize(trace.type, transform, fullLayout);
431
+ recordMinTextSize(trace.type === 'histogram' ? 'bar' : trace.type, transform, fullLayout);
432
432
  calcBar.transform = transform;
433
433
 
434
434
  transition(textSelection, fullLayout, opts, makeOnCompleteCallback)
@@ -3,6 +3,8 @@
3
3
  var barAttrs = require('../bar/attributes');
4
4
  var axisHoverFormat = require('../../plots/cartesian/axis_format_attributes').axisHoverFormat;
5
5
  var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
6
+ var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
7
+ var fontAttrs = require('../../plots/font_attributes');
6
8
  var makeBinAttrs = require('./bin_attributes');
7
9
  var constants = require('./constants');
8
10
  var extendFlat = require('../../lib/extend').extendFlat;
@@ -198,6 +200,44 @@ module.exports = {
198
200
  keys: constants.eventDataKeys
199
201
  }),
200
202
 
203
+ texttemplate: texttemplateAttrs({
204
+ arrayOk: false,
205
+ editType: 'plot'
206
+ }, {
207
+ keys: ['label', 'value']
208
+ }),
209
+
210
+ textposition: extendFlat({}, barAttrs.textposition, {
211
+ arrayOk: false
212
+ }),
213
+
214
+ textfont: fontAttrs({
215
+ arrayOk: false,
216
+ editType: 'plot',
217
+ colorEditType: 'style',
218
+ description: 'Sets the text font.'
219
+ }),
220
+
221
+ outsidetextfont: fontAttrs({
222
+ arrayOk: false,
223
+ editType: 'plot',
224
+ colorEditType: 'style',
225
+ description: 'Sets the font used for `text` lying outside the bar.'
226
+ }),
227
+
228
+ insidetextfont: fontAttrs({
229
+ arrayOk: false,
230
+ editType: 'plot',
231
+ colorEditType: 'style',
232
+ description: 'Sets the font used for `text` lying inside the bar.'
233
+ }),
234
+
235
+ insidetextanchor: barAttrs.insidetextanchor,
236
+
237
+ textangle: barAttrs.textangle,
238
+ cliponaxis: barAttrs.cliponaxis,
239
+ constraintext: barAttrs.constraintext,
240
+
201
241
  marker: barAttrs.marker,
202
242
 
203
243
  offsetgroup: barAttrs.offsetgroup,
@@ -4,6 +4,7 @@ var Registry = require('../../registry');
4
4
  var Lib = require('../../lib');
5
5
  var Color = require('../../components/color');
6
6
 
7
+ var handleText = require('../bar/defaults').handleText;
7
8
  var handleStyleDefaults = require('../bar/style_defaults');
8
9
  var attributes = require('./attributes');
9
10
 
@@ -22,6 +23,16 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
22
23
  }
23
24
 
24
25
  coerce('text');
26
+ var textposition = coerce('textposition');
27
+ handleText(traceIn, traceOut, layout, coerce, textposition, {
28
+ moduleHasSelected: true,
29
+ moduleHasUnselected: true,
30
+ moduleHasConstrain: true,
31
+ moduleHasCliponaxis: true,
32
+ moduleHasTextangle: true,
33
+ moduleHasInsideanchor: true
34
+ });
35
+
25
36
  coerce('hovertext');
26
37
  coerce('hovertemplate');
27
38
  coerce('xhoverformat');
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.6.1';
4
+ exports.version = '2.7.0';