plotly.js 2.6.2 → 2.8.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +3 -3
  3. package/dist/README.md +26 -26
  4. package/dist/plot-schema.json +1015 -407
  5. package/dist/plotly-basic.js +568 -225
  6. package/dist/plotly-basic.min.js +4 -4
  7. package/dist/plotly-cartesian.js +1029 -371
  8. package/dist/plotly-cartesian.min.js +3 -3
  9. package/dist/plotly-finance.js +618 -227
  10. package/dist/plotly-finance.min.js +4 -4
  11. package/dist/plotly-geo-assets.js +2 -2
  12. package/dist/plotly-geo.js +564 -223
  13. package/dist/plotly-geo.min.js +2 -2
  14. package/dist/plotly-gl2d.js +580 -224
  15. package/dist/plotly-gl2d.min.js +2 -2
  16. package/dist/plotly-gl3d.js +564 -223
  17. package/dist/plotly-gl3d.min.js +2 -2
  18. package/dist/plotly-mapbox.js +570 -226
  19. package/dist/plotly-mapbox.min.js +2 -2
  20. package/dist/plotly-strict.js +1253 -592
  21. package/dist/plotly-strict.min.js +3 -3
  22. package/dist/plotly-with-meta.js +1345 -654
  23. package/dist/plotly.js +1307 -646
  24. package/dist/plotly.min.js +10 -10
  25. package/package.json +9 -9
  26. package/src/components/colorbar/attributes.js +29 -20
  27. package/src/components/colorbar/defaults.js +30 -8
  28. package/src/components/colorbar/draw.js +398 -141
  29. package/src/components/drawing/index.js +6 -3
  30. package/src/components/fx/hover.js +16 -17
  31. package/src/components/fx/hoverlabel_defaults.js +4 -2
  32. package/src/components/fx/layout_attributes.js +14 -4
  33. package/src/components/fx/layout_defaults.js +2 -0
  34. package/src/components/legend/attributes.js +7 -0
  35. package/src/components/legend/defaults.js +24 -7
  36. package/src/components/titles/index.js +8 -2
  37. package/src/plot_api/plot_api.js +38 -9
  38. package/src/plots/font_attributes.js +3 -0
  39. package/src/plots/layout_attributes.js +1 -0
  40. package/src/plots/mapbox/mapbox.js +6 -3
  41. package/src/plots/plots.js +7 -15
  42. package/src/traces/bar/plot.js +1 -1
  43. package/src/traces/contour/attributes.js +12 -0
  44. package/src/traces/contour/defaults.js +9 -1
  45. package/src/traces/heatmap/attributes.js +16 -0
  46. package/src/traces/heatmap/defaults.js +2 -0
  47. package/src/traces/heatmap/label_defaults.js +13 -0
  48. package/src/traces/heatmap/plot.js +203 -4
  49. package/src/traces/histogram/attributes.js +40 -0
  50. package/src/traces/histogram/defaults.js +11 -0
  51. package/src/traces/histogram2d/attributes.js +8 -0
  52. package/src/traces/histogram2d/defaults.js +4 -0
  53. package/src/traces/histogram2dcontour/attributes.js +3 -1
  54. package/src/traces/histogram2dcontour/defaults.js +8 -1
  55. package/src/traces/pie/calc.js +3 -1
  56. package/src/version.js +1 -1
  57. package/tasks/test_mock.js +1 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * plotly.js (gl3d) v2.6.2
2
+ * plotly.js (gl3d) v2.8.0
3
3
  * Copyright 2012-2021, Plotly, Inc.
4
4
  * All rights reserved.
5
5
  * Licensed under the MIT license
@@ -22254,13 +22254,11 @@ var overrideAll = _dereq_('../../plot_api/edit_types').overrideAll;
22254
22254
 
22255
22255
 
22256
22256
  module.exports = overrideAll({
22257
- // TODO: only right is supported currently
22258
- // orient: {
22259
- // valType: 'enumerated',
22260
- // values: ['left', 'right', 'top', 'bottom'],
22261
- // dflt: 'right',
22262
- //
22263
- // },
22257
+ orientation: {
22258
+ valType: 'enumerated',
22259
+ values: ['h', 'v'],
22260
+ dflt: 'v',
22261
+ },
22264
22262
  thicknessmode: {
22265
22263
  valType: 'enumerated',
22266
22264
  values: ['fraction', 'pixels'],
@@ -22283,14 +22281,12 @@ module.exports = overrideAll({
22283
22281
  },
22284
22282
  x: {
22285
22283
  valType: 'number',
22286
- dflt: 1.02,
22287
22284
  min: -2,
22288
22285
  max: 3,
22289
22286
  },
22290
22287
  xanchor: {
22291
22288
  valType: 'enumerated',
22292
22289
  values: ['left', 'center', 'right'],
22293
- dflt: 'left',
22294
22290
  },
22295
22291
  xpad: {
22296
22292
  valType: 'number',
@@ -22299,14 +22295,12 @@ module.exports = overrideAll({
22299
22295
  },
22300
22296
  y: {
22301
22297
  valType: 'number',
22302
- dflt: 0.5,
22303
22298
  min: -2,
22304
22299
  max: 3,
22305
22300
  },
22306
22301
  yanchor: {
22307
22302
  valType: 'enumerated',
22308
22303
  values: ['top', 'middle', 'bottom'],
22309
- dflt: 'middle',
22310
22304
  },
22311
22305
  ypad: {
22312
22306
  valType: 'number',
@@ -22338,15 +22332,21 @@ module.exports = overrideAll({
22338
22332
  ticks: extendFlat({}, axesAttrs.ticks, {dflt: ''}),
22339
22333
  ticklabeloverflow: extendFlat({}, axesAttrs.ticklabeloverflow, {
22340
22334
  }),
22335
+
22336
+ // ticklabelposition: not used directly, as values depend on orientation
22337
+ // left/right options are for x axes, and top/bottom options are for y axes
22341
22338
  ticklabelposition: {
22342
22339
  valType: 'enumerated',
22343
22340
  values: [
22344
22341
  'outside', 'inside',
22345
22342
  'outside top', 'inside top',
22343
+ 'outside left', 'inside left',
22344
+ 'outside right', 'inside right',
22346
22345
  'outside bottom', 'inside bottom'
22347
22346
  ],
22348
22347
  dflt: 'outside',
22349
22348
  },
22349
+
22350
22350
  ticklen: axesAttrs.ticklen,
22351
22351
  tickwidth: axesAttrs.tickwidth,
22352
22352
  tickcolor: axesAttrs.tickcolor,
@@ -22373,7 +22373,6 @@ module.exports = overrideAll({
22373
22373
  side: {
22374
22374
  valType: 'enumerated',
22375
22375
  values: ['right', 'top', 'bottom'],
22376
- dflt: 'top',
22377
22376
  }
22378
22377
  },
22379
22378
 
@@ -22432,23 +22431,30 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
22432
22431
  return Lib.coerce(colorbarIn, colorbarOut, attributes, attr, dflt);
22433
22432
  }
22434
22433
 
22434
+ var margin = layout.margin || {t: 0, b: 0, l: 0, r: 0};
22435
+ var w = layout.width - margin.l - margin.r;
22436
+ var h = layout.height - margin.t - margin.b;
22437
+
22438
+ var orientation = coerce('orientation');
22439
+ var isVertical = orientation === 'v';
22440
+
22435
22441
  var thicknessmode = coerce('thicknessmode');
22436
22442
  coerce('thickness', (thicknessmode === 'fraction') ?
22437
- 30 / (layout.width - layout.margin.l - layout.margin.r) :
22443
+ 30 / (isVertical ? w : h) :
22438
22444
  30
22439
22445
  );
22440
22446
 
22441
22447
  var lenmode = coerce('lenmode');
22442
22448
  coerce('len', (lenmode === 'fraction') ?
22443
22449
  1 :
22444
- layout.height - layout.margin.t - layout.margin.b
22450
+ isVertical ? h : w
22445
22451
  );
22446
22452
 
22447
- coerce('x');
22448
- coerce('xanchor');
22453
+ coerce('x', isVertical ? 1.02 : 0.5);
22454
+ coerce('xanchor', isVertical ? 'left' : 'center');
22449
22455
  coerce('xpad');
22450
- coerce('y');
22451
- coerce('yanchor');
22456
+ coerce('y', isVertical ? 0.5 : 1.02);
22457
+ coerce('yanchor', isVertical ? 'middle' : 'bottom');
22452
22458
  coerce('ypad');
22453
22459
  Lib.noneOrAll(colorbarIn, colorbarOut, ['x', 'y']);
22454
22460
 
@@ -22458,7 +22464,22 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
22458
22464
  coerce('borderwidth');
22459
22465
  coerce('bgcolor');
22460
22466
 
22461
- var ticklabelposition = coerce('ticklabelposition');
22467
+ var ticklabelposition = Lib.coerce(colorbarIn, colorbarOut, {
22468
+ ticklabelposition: {
22469
+ valType: 'enumerated',
22470
+ dflt: 'outside',
22471
+ values: isVertical ? [
22472
+ 'outside', 'inside',
22473
+ 'outside top', 'inside top',
22474
+ 'outside bottom', 'inside bottom'
22475
+ ] : [
22476
+ 'outside', 'inside',
22477
+ 'outside left', 'inside left',
22478
+ 'outside right', 'inside right'
22479
+ ]
22480
+ }
22481
+ }, 'ticklabelposition');
22482
+
22462
22483
  coerce('ticklabeloverflow', ticklabelposition.indexOf('inside') !== -1 ? 'hide past domain' : 'hide past div');
22463
22484
 
22464
22485
  handleTickValueDefaults(colorbarIn, colorbarOut, coerce, 'linear');
@@ -22480,7 +22501,7 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
22480
22501
  size: Lib.bigFont(tickFont.size)
22481
22502
  });
22482
22503
  Lib.coerceFont(coerce, 'title.font', dfltTitleFont);
22483
- coerce('title.side');
22504
+ coerce('title.side', isVertical ? 'top' : 'right');
22484
22505
  };
22485
22506
 
22486
22507
  },{"../../lib":252,"../../plot_api/plot_template":290,"../../plots/cartesian/prefix_suffix_defaults":320,"../../plots/cartesian/tick_label_defaults":325,"../../plots/cartesian/tick_mark_defaults":326,"../../plots/cartesian/tick_value_defaults":327,"./attributes":120}],123:[function(_dereq_,module,exports){
@@ -22653,6 +22674,21 @@ function makeColorBarData(gd) {
22653
22674
  }
22654
22675
 
22655
22676
  function drawColorBar(g, opts, gd) {
22677
+ var isVertical = opts.orientation === 'v';
22678
+ var len = opts.len;
22679
+ var lenmode = opts.lenmode;
22680
+ var thickness = opts.thickness;
22681
+ var thicknessmode = opts.thicknessmode;
22682
+ var outlinewidth = opts.outlinewidth;
22683
+ var borderwidth = opts.borderwidth;
22684
+ var bgcolor = opts.bgcolor;
22685
+ var xanchor = opts.xanchor;
22686
+ var yanchor = opts.yanchor;
22687
+ var xpad = opts.xpad;
22688
+ var ypad = opts.ypad;
22689
+ var optsX = opts.x;
22690
+ var optsY = isVertical ? opts.y : 1 - opts.y;
22691
+
22656
22692
  var fullLayout = gd._fullLayout;
22657
22693
  var gs = fullLayout._size;
22658
22694
 
@@ -22682,42 +22718,64 @@ function drawColorBar(g, opts, gd) {
22682
22718
  // when the colorbar itself is pushing the margins.
22683
22719
  // but then the fractional size is calculated based on the
22684
22720
  // actual graph size, so that the axes will size correctly.
22685
- var thickPx = Math.round(opts.thickness * (opts.thicknessmode === 'fraction' ? gs.w : 1));
22686
- var thickFrac = thickPx / gs.w;
22687
- var lenPx = Math.round(opts.len * (opts.lenmode === 'fraction' ? gs.h : 1));
22688
- var lenFrac = lenPx / gs.h;
22689
- var xpadFrac = opts.xpad / gs.w;
22690
- var yExtraPx = (opts.borderwidth + opts.outlinewidth) / 2;
22691
- var ypadFrac = opts.ypad / gs.h;
22721
+ var thickPx = Math.round(thickness * (thicknessmode === 'fraction' ? (isVertical ? gs.w : gs.h) : 1));
22722
+ var thickFrac = thickPx / (isVertical ? gs.w : gs.h);
22723
+ var lenPx = Math.round(len * (lenmode === 'fraction' ? (isVertical ? gs.h : gs.w) : 1));
22724
+ var lenFrac = lenPx / (isVertical ? gs.h : gs.w);
22692
22725
 
22693
22726
  // x positioning: do it initially just for left anchor,
22694
22727
  // then fix at the end (since we don't know the width yet)
22695
- var xLeft = Math.round(opts.x * gs.w + opts.xpad);
22696
- // for dragging... this is getting a little muddled...
22697
- var xLeftFrac = opts.x - thickFrac * ({center: 0.5, right: 1}[opts.xanchor] || 0);
22728
+ var uPx = Math.round(isVertical ?
22729
+ optsX * gs.w + xpad :
22730
+ optsY * gs.h + ypad
22731
+ );
22698
22732
 
22699
- // y positioning we can do correctly from the start
22700
- var yBottomFrac = opts.y + lenFrac * (({top: -0.5, bottom: 0.5}[opts.yanchor] || 0) - 0.5);
22701
- var yBottomPx = Math.round(gs.h * (1 - yBottomFrac));
22702
- var yTopPx = yBottomPx - lenPx;
22733
+ var xRatio = {center: 0.5, right: 1}[xanchor] || 0;
22734
+ var yRatio = {top: 1, middle: 0.5}[yanchor] || 0;
22735
+
22736
+ // for dragging... this is getting a little muddled...
22737
+ var uFrac = isVertical ?
22738
+ optsX - xRatio * thickFrac :
22739
+ optsY - yRatio * thickFrac;
22740
+
22741
+ // y/x positioning (for v/h) we can do correctly from the start
22742
+ var vFrac = isVertical ?
22743
+ optsY - yRatio * lenFrac :
22744
+ optsX - xRatio * lenFrac;
22745
+
22746
+ var vPx = Math.round(isVertical ?
22747
+ gs.h * (1 - vFrac) :
22748
+ gs.w * vFrac
22749
+ );
22703
22750
 
22704
22751
  // stash a few things for makeEditable
22705
22752
  opts._lenFrac = lenFrac;
22706
22753
  opts._thickFrac = thickFrac;
22707
- opts._xLeftFrac = xLeftFrac;
22708
- opts._yBottomFrac = yBottomFrac;
22754
+ opts._uFrac = uFrac;
22755
+ opts._vFrac = vFrac;
22709
22756
 
22710
22757
  // stash mocked axis for contour label formatting
22711
22758
  var ax = opts._axis = mockColorBarAxis(gd, opts, zrange);
22712
22759
 
22713
22760
  // position can't go in through supplyDefaults
22714
22761
  // because that restricts it to [0,1]
22715
- ax.position = opts.x + xpadFrac + thickFrac;
22762
+ ax.position = thickFrac + (isVertical ?
22763
+ optsX + xpad / gs.w :
22764
+ optsY + ypad / gs.h
22765
+ );
22766
+
22767
+ var topOrBottom = ['top', 'bottom'].indexOf(titleSide) !== -1;
22768
+
22769
+ if(isVertical && topOrBottom) {
22770
+ ax.title.side = titleSide;
22771
+ ax.titlex = optsX + xpad / gs.w;
22772
+ ax.titley = vFrac + (title.side === 'top' ? lenFrac - ypad / gs.h : ypad / gs.h);
22773
+ }
22716
22774
 
22717
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22775
+ if(!isVertical && !topOrBottom) {
22718
22776
  ax.title.side = titleSide;
22719
- ax.titlex = opts.x + xpadFrac;
22720
- ax.titley = yBottomFrac + (title.side === 'top' ? lenFrac - ypadFrac : ypadFrac);
22777
+ ax.titley = optsY + ypad / gs.h;
22778
+ ax.titlex = vFrac + xpad / gs.w; // right side
22721
22779
  }
22722
22780
 
22723
22781
  if(line.color && opts.tickmode === 'auto') {
@@ -22725,7 +22783,7 @@ function drawColorBar(g, opts, gd) {
22725
22783
  ax.tick0 = levelsIn.start;
22726
22784
  var dtick = levelsIn.size;
22727
22785
  // expand if too many contours, so we don't get too many ticks
22728
- var autoNtick = Lib.constrain((yBottomPx - yTopPx) / 50, 4, 15) + 1;
22786
+ var autoNtick = Lib.constrain(lenPx / 50, 4, 15) + 1;
22729
22787
  var dtFactor = (zrange[1] - zrange[0]) / ((opts.nticks || autoNtick) * dtick);
22730
22788
  if(dtFactor > 1) {
22731
22789
  var dtexp = Math.pow(10, Math.floor(Math.log(dtFactor) / Math.LN10));
@@ -22742,9 +22800,12 @@ function drawColorBar(g, opts, gd) {
22742
22800
 
22743
22801
  // set domain after init, because we may want to
22744
22802
  // allow it outside [0,1]
22745
- ax.domain = [
22746
- yBottomFrac + ypadFrac,
22747
- yBottomFrac + lenFrac - ypadFrac
22803
+ ax.domain = isVertical ? [
22804
+ vFrac + ypad / gs.h,
22805
+ vFrac + lenFrac - ypad / gs.h
22806
+ ] : [
22807
+ vFrac + xpad / gs.w,
22808
+ vFrac + lenFrac - xpad / gs.w
22748
22809
  ];
22749
22810
 
22750
22811
  ax.setScale();
@@ -22754,9 +22815,13 @@ function drawColorBar(g, opts, gd) {
22754
22815
  var titleCont = g.select('.' + cn.cbtitleunshift)
22755
22816
  .attr('transform', strTranslate(-Math.round(gs.l), -Math.round(gs.t)));
22756
22817
 
22818
+ var ticklabelposition = ax.ticklabelposition;
22819
+ var titleFontSize = ax.title.font.size;
22820
+
22757
22821
  var axLayer = g.select('.' + cn.cbaxis);
22758
22822
  var titleEl;
22759
22823
  var titleHeight = 0;
22824
+ var titleWidth = 0;
22760
22825
 
22761
22826
  function drawTitle(titleClass, titleOpts) {
22762
22827
  var dfltTitleOpts = {
@@ -22781,58 +22846,102 @@ function drawColorBar(g, opts, gd) {
22781
22846
  }
22782
22847
 
22783
22848
  function drawDummyTitle() {
22784
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22785
- // draw the title so we know how much room it needs
22786
- // when we squish the axis. This one only applies to
22787
- // top or bottom titles, not right side.
22788
- var x = gs.l + (opts.x + xpadFrac) * gs.w;
22789
- var fontSize = ax.title.font.size;
22790
- var y;
22849
+ // draw the title so we know how much room it needs
22850
+ // when we squish the axis.
22851
+ // On vertical colorbars this only applies to top or bottom titles, not right side.
22852
+ // On horizontal colorbars this only applies to right, etc.
22853
+
22854
+ if(
22855
+ (isVertical && topOrBottom) ||
22856
+ (!isVertical && !topOrBottom)
22857
+ ) {
22858
+ var x, y;
22791
22859
 
22792
22860
  if(titleSide === 'top') {
22793
- y = (1 - (yBottomFrac + lenFrac - ypadFrac)) * gs.h +
22794
- gs.t + 3 + fontSize * 0.75;
22795
- } else {
22796
- y = (1 - (yBottomFrac + ypadFrac)) * gs.h +
22797
- gs.t - 3 - fontSize * 0.25;
22861
+ x = xpad + gs.l + gs.w * optsX;
22862
+ y = ypad + gs.t + gs.h * (1 - vFrac - lenFrac) + 3 + titleFontSize * 0.75;
22863
+ }
22864
+
22865
+ if(titleSide === 'bottom') {
22866
+ x = xpad + gs.l + gs.w * optsX;
22867
+ y = ypad + gs.t + gs.h * (1 - vFrac) - 3 - titleFontSize * 0.25;
22868
+ }
22869
+
22870
+ if(titleSide === 'right') {
22871
+ y = ypad + gs.t + gs.h * optsY + 3 + titleFontSize * 0.75;
22872
+ x = xpad + gs.l + gs.w * vFrac;
22798
22873
  }
22874
+
22799
22875
  drawTitle(ax._id + 'title', {
22800
- attributes: {x: x, y: y, 'text-anchor': 'start'}
22876
+ attributes: {x: x, y: y, 'text-anchor': isVertical ? 'start' : 'middle'}
22801
22877
  });
22802
22878
  }
22803
22879
  }
22804
22880
 
22805
22881
  function drawCbTitle() {
22806
- if(['top', 'bottom'].indexOf(titleSide) === -1) {
22807
- var fontSize = ax.title.font.size;
22808
- var y = ax._offset + ax._length / 2;
22809
- var x = gs.l + (ax.position || 0) * gs.w + ((ax.side === 'right') ?
22810
- 10 + fontSize * ((ax.showticklabels ? 1 : 0.5)) :
22811
- -10 - fontSize * ((ax.showticklabels ? 0.5 : 0)));
22812
-
22813
- // the 'h' + is a hack to get around the fact that
22814
- // convertToTspans rotates any 'y...' class by 90 degrees.
22815
- // TODO: find a better way to control this.
22816
- drawTitle('h' + ax._id + 'title', {
22882
+ if(
22883
+ (isVertical && !topOrBottom) ||
22884
+ (!isVertical && topOrBottom)
22885
+ ) {
22886
+ var pos = ax.position || 0;
22887
+ var mid = ax._offset + ax._length / 2;
22888
+ var x, y;
22889
+
22890
+ if(titleSide === 'right') {
22891
+ y = mid;
22892
+ x = gs.l + gs.w * pos + 10 + titleFontSize * (
22893
+ ax.showticklabels ? 1 : 0.5
22894
+ );
22895
+ } else {
22896
+ x = mid;
22897
+
22898
+ if(titleSide === 'bottom') {
22899
+ y = gs.t + gs.h * pos + 10 + (
22900
+ ticklabelposition.indexOf('inside') === -1 ?
22901
+ ax.tickfont.size :
22902
+ 0
22903
+ ) + (
22904
+ ax.ticks !== 'intside' ?
22905
+ opts.ticklen || 0 :
22906
+ 0
22907
+ );
22908
+ }
22909
+
22910
+ if(titleSide === 'top') {
22911
+ var nlines = title.text.split('<br>').length;
22912
+ y = gs.t + gs.h * pos + 10 - thickPx - LINE_SPACING * titleFontSize * nlines;
22913
+ }
22914
+ }
22915
+
22916
+ drawTitle((isVertical ?
22917
+ // the 'h' + is a hack to get around the fact that
22918
+ // convertToTspans rotates any 'y...' class by 90 degrees.
22919
+ // TODO: find a better way to control this.
22920
+ 'h' :
22921
+ 'v'
22922
+ ) + ax._id + 'title', {
22817
22923
  avoid: {
22818
22924
  selection: d3.select(gd).selectAll('g.' + ax._id + 'tick'),
22819
22925
  side: titleSide,
22820
- offsetLeft: gs.l,
22821
- offsetTop: 0,
22822
- maxShift: fullLayout.width
22926
+ offsetTop: isVertical ? 0 : gs.t,
22927
+ offsetLeft: isVertical ? gs.l : 0,
22928
+ maxShift: isVertical ? fullLayout.width : fullLayout.height
22823
22929
  },
22824
22930
  attributes: {x: x, y: y, 'text-anchor': 'middle'},
22825
- transform: {rotate: '-90', offset: 0}
22931
+ transform: {rotate: isVertical ? -90 : 0, offset: 0}
22826
22932
  });
22827
22933
  }
22828
22934
  }
22829
22935
 
22830
22936
  function drawAxis() {
22831
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22937
+ if(
22938
+ (!isVertical && !topOrBottom) ||
22939
+ (isVertical && topOrBottom)
22940
+ ) {
22832
22941
  // squish the axis top to make room for the title
22833
22942
  var titleGroup = g.select('.' + cn.cbtitle);
22834
22943
  var titleText = titleGroup.select('text');
22835
- var titleTrans = [-opts.outlinewidth / 2, opts.outlinewidth / 2];
22944
+ var titleTrans = [-outlinewidth / 2, outlinewidth / 2];
22836
22945
  var mathJaxNode = titleGroup
22837
22946
  .select('.h' + ax._id + 'title-math-group')
22838
22947
  .node();
@@ -22840,39 +22949,63 @@ function drawColorBar(g, opts, gd) {
22840
22949
  if(titleText.node()) {
22841
22950
  lineSize = parseInt(titleText.node().style.fontSize, 10) * LINE_SPACING;
22842
22951
  }
22952
+
22953
+ var bb;
22843
22954
  if(mathJaxNode) {
22844
- titleHeight = Drawing.bBox(mathJaxNode).height;
22955
+ bb = Drawing.bBox(mathJaxNode);
22956
+ titleWidth = bb.width;
22957
+ titleHeight = bb.height;
22845
22958
  if(titleHeight > lineSize) {
22846
22959
  // not entirely sure how mathjax is doing
22847
22960
  // vertical alignment, but this seems to work.
22848
22961
  titleTrans[1] -= (titleHeight - lineSize) / 2;
22849
22962
  }
22850
22963
  } else if(titleText.node() && !titleText.classed(cn.jsPlaceholder)) {
22851
- titleHeight = Drawing.bBox(titleText.node()).height;
22964
+ bb = Drawing.bBox(titleText.node());
22965
+ titleWidth = bb.width;
22966
+ titleHeight = bb.height;
22852
22967
  }
22853
- if(titleHeight) {
22854
- // buffer btwn colorbar and title
22855
- // TODO: configurable
22856
- titleHeight += 5;
22857
22968
 
22858
- if(titleSide === 'top') {
22859
- ax.domain[1] -= titleHeight / gs.h;
22860
- titleTrans[1] *= -1;
22861
- } else {
22862
- ax.domain[0] += titleHeight / gs.h;
22863
- var nlines = svgTextUtils.lineCount(titleText);
22864
- titleTrans[1] += (1 - nlines) * lineSize;
22969
+ if(isVertical) {
22970
+ if(titleHeight) {
22971
+ // buffer btwn colorbar and title
22972
+ // TODO: configurable
22973
+ titleHeight += 5;
22974
+
22975
+ if(titleSide === 'top') {
22976
+ ax.domain[1] -= titleHeight / gs.h;
22977
+ titleTrans[1] *= -1;
22978
+ } else {
22979
+ ax.domain[0] += titleHeight / gs.h;
22980
+ var nlines = svgTextUtils.lineCount(titleText);
22981
+ titleTrans[1] += (1 - nlines) * lineSize;
22982
+ }
22983
+
22984
+ titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22985
+ ax.setScale();
22865
22986
  }
22987
+ } else { // horizontal colorbars
22988
+ if(titleWidth) {
22989
+ if(titleSide === 'right') {
22990
+ ax.domain[0] += (titleWidth + titleFontSize / 2) / gs.w;
22991
+ }
22866
22992
 
22867
- titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22868
- ax.setScale();
22993
+ titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22994
+ ax.setScale();
22995
+ }
22869
22996
  }
22870
22997
  }
22871
22998
 
22872
22999
  g.selectAll('.' + cn.cbfills + ',.' + cn.cblines)
22873
- .attr('transform', strTranslate(0, Math.round(gs.h * (1 - ax.domain[1]))));
23000
+ .attr('transform', isVertical ?
23001
+ strTranslate(0, Math.round(gs.h * (1 - ax.domain[1]))) :
23002
+ strTranslate(Math.round(gs.w * ax.domain[0]), 0)
23003
+ );
22874
23004
 
22875
- axLayer.attr('transform', strTranslate(0, Math.round(-gs.t)));
23005
+ axLayer.attr('transform', isVertical ?
23006
+ strTranslate(0, Math.round(-gs.t)) :
23007
+ strTranslate(Math.round(-gs.l), 0)
23008
+ );
22876
23009
 
22877
23010
  var fills = g.select('.' + cn.cbfills)
22878
23011
  .selectAll('rect.' + cn.cbfill)
@@ -22898,20 +23031,22 @@ function drawColorBar(g, opts, gd) {
22898
23031
 
22899
23032
  // offset the side adjoining the next rectangle so they
22900
23033
  // overlap, to prevent antialiasing gaps
22901
- z[1] = Lib.constrain(z[1] + (z[1] > z[0]) ? 1 : -1, zBounds[0], zBounds[1]);
22902
-
23034
+ if(isVertical) {
23035
+ z[1] = Lib.constrain(z[1] + (z[1] > z[0]) ? 1 : -1, zBounds[0], zBounds[1]);
23036
+ } /* else {
23037
+ // TODO: horizontal case
23038
+ } */
22903
23039
 
22904
23040
  // Colorbar cannot currently support opacities so we
22905
23041
  // use an opaque fill even when alpha channels present
22906
- var fillEl = d3.select(this).attr({
22907
- x: xLeft,
22908
- width: Math.max(thickPx, 2),
22909
- y: d3.min(z),
22910
- height: Math.max(d3.max(z) - d3.min(z), 2),
22911
- });
23042
+ var fillEl = d3.select(this)
23043
+ .attr(isVertical ? 'x' : 'y', uPx)
23044
+ .attr(isVertical ? 'y' : 'x', d3.min(z))
23045
+ .attr(isVertical ? 'width' : 'height', Math.max(thickPx, 2))
23046
+ .attr(isVertical ? 'height' : 'width', Math.max(d3.max(z) - d3.min(z), 2));
22912
23047
 
22913
23048
  if(opts._fillgradient) {
22914
- Drawing.gradient(fillEl, gd, opts._id, 'vertical', opts._fillgradient, 'fill');
23049
+ Drawing.gradient(fillEl, gd, opts._id, isVertical ? 'vertical' : 'horizontalreversed', opts._fillgradient, 'fill');
22915
23050
  } else {
22916
23051
  // tinycolor can't handle exponents and
22917
23052
  // at this scale, removing it makes no difference.
@@ -22927,17 +23062,23 @@ function drawColorBar(g, opts, gd) {
22927
23062
  .classed(cn.cbline, true);
22928
23063
  lines.exit().remove();
22929
23064
  lines.each(function(d) {
23065
+ var a = uPx;
23066
+ var b = (Math.round(ax.c2p(d)) + (line.width / 2) % 1);
23067
+
22930
23068
  d3.select(this)
22931
- .attr('d', 'M' + xLeft + ',' +
22932
- (Math.round(ax.c2p(d)) + (line.width / 2) % 1) + 'h' + thickPx)
23069
+ .attr('d', 'M' +
23070
+ (isVertical ? a + ',' + b : b + ',' + a) +
23071
+ (isVertical ? 'h' : 'v') +
23072
+ thickPx
23073
+ )
22933
23074
  .call(Drawing.lineGroupStyle, line.width, lineColormap(d), line.dash);
22934
23075
  });
22935
23076
 
22936
23077
  // force full redraw of labels and ticks
22937
23078
  axLayer.selectAll('g.' + ax._id + 'tick,path').remove();
22938
23079
 
22939
- var shift = xLeft + thickPx +
22940
- (opts.outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
23080
+ var shift = uPx + thickPx +
23081
+ (outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
22941
23082
 
22942
23083
  var vals = Axes.calcTicks(ax);
22943
23084
  var tickSign = Axes.getTickSigns(ax)[2];
@@ -22962,83 +23103,211 @@ function drawColorBar(g, opts, gd) {
22962
23103
  // TODO: why are we redrawing multiple times now with this?
22963
23104
  // I guess autoMargin doesn't like being post-promise?
22964
23105
  function positionCB() {
22965
- var innerWidth = thickPx + opts.outlinewidth / 2;
22966
- if(ax.ticklabelposition.indexOf('inside') === -1) {
22967
- innerWidth += Drawing.bBox(axLayer.node()).width;
23106
+ var bb;
23107
+ var innerThickness = thickPx + outlinewidth / 2;
23108
+ if(ticklabelposition.indexOf('inside') === -1) {
23109
+ bb = Drawing.bBox(axLayer.node());
23110
+ innerThickness += isVertical ? bb.width : bb.height;
22968
23111
  }
22969
23112
 
22970
23113
  titleEl = titleCont.select('text');
22971
23114
 
23115
+ var titleWidth = 0;
23116
+
23117
+ var topSideVertical = isVertical && titleSide === 'top';
23118
+ var rightSideHorizontal = !isVertical && titleSide === 'right';
23119
+
23120
+ var moveY = 0;
23121
+
22972
23122
  if(titleEl.node() && !titleEl.classed(cn.jsPlaceholder)) {
23123
+ var _titleHeight;
23124
+
22973
23125
  var mathJaxNode = titleCont.select('.h' + ax._id + 'title-math-group').node();
22974
- var titleWidth;
22975
- if(mathJaxNode && ['top', 'bottom'].indexOf(titleSide) !== -1) {
22976
- titleWidth = Drawing.bBox(mathJaxNode).width;
23126
+ if(mathJaxNode && (
23127
+ (isVertical && topOrBottom) ||
23128
+ (!isVertical && !topOrBottom)
23129
+ )) {
23130
+ bb = Drawing.bBox(mathJaxNode);
23131
+ titleWidth = bb.width;
23132
+ _titleHeight = bb.height;
22977
23133
  } else {
22978
23134
  // note: the formula below works for all title sides,
22979
23135
  // (except for top/bottom mathjax, above)
22980
23136
  // but the weird gs.l is because the titleunshift
22981
23137
  // transform gets removed by Drawing.bBox
22982
- titleWidth = Drawing.bBox(titleCont.node()).right - xLeft - gs.l;
23138
+ bb = Drawing.bBox(titleCont.node());
23139
+ titleWidth = bb.right - gs.l - (isVertical ? uPx : vPx);
23140
+ _titleHeight = bb.bottom - gs.t - (isVertical ? vPx : uPx);
23141
+
23142
+ if(
23143
+ !isVertical && titleSide === 'top'
23144
+ ) {
23145
+ innerThickness += bb.height;
23146
+ moveY = bb.height;
23147
+ }
22983
23148
  }
22984
- innerWidth = Math.max(innerWidth, titleWidth);
23149
+
23150
+ if(rightSideHorizontal) {
23151
+ titleEl.attr('transform', strTranslate(titleWidth / 2 + titleFontSize / 2, 0));
23152
+
23153
+ titleWidth *= 2;
23154
+ }
23155
+
23156
+ innerThickness = Math.max(innerThickness,
23157
+ isVertical ? titleWidth : _titleHeight
23158
+ );
22985
23159
  }
22986
23160
 
22987
- var outerwidth = 2 * opts.xpad + innerWidth + opts.borderwidth + opts.outlinewidth / 2;
22988
- var outerheight = yBottomPx - yTopPx;
23161
+ var outerThickness = (isVertical ?
23162
+ xpad :
23163
+ ypad
23164
+ ) * 2 + innerThickness + borderwidth + outlinewidth / 2;
22989
23165
 
22990
- g.select('.' + cn.cbbg).attr({
22991
- x: xLeft - opts.xpad - (opts.borderwidth + opts.outlinewidth) / 2,
22992
- y: yTopPx - yExtraPx,
22993
- width: Math.max(outerwidth, 2),
22994
- height: Math.max(outerheight + 2 * yExtraPx, 2)
22995
- })
22996
- .call(Color.fill, opts.bgcolor)
22997
- .call(Color.stroke, opts.bordercolor)
22998
- .style('stroke-width', opts.borderwidth);
23166
+ var hColorbarMoveTitle = 0;
23167
+ if(!isVertical && title.text && yanchor === 'bottom' && optsY <= 0) {
23168
+ hColorbarMoveTitle = outerThickness / 2;
22999
23169
 
23000
- g.selectAll('.' + cn.cboutline).attr({
23001
- x: xLeft,
23002
- y: yTopPx + opts.ypad + (titleSide === 'top' ? titleHeight : 0),
23003
- width: Math.max(thickPx, 2),
23004
- height: Math.max(outerheight - 2 * opts.ypad - titleHeight, 2)
23005
- })
23170
+ outerThickness += hColorbarMoveTitle;
23171
+ moveY += hColorbarMoveTitle;
23172
+ }
23173
+ fullLayout._hColorbarMoveTitle = hColorbarMoveTitle;
23174
+ fullLayout._hColorbarMoveCBTitle = moveY;
23175
+
23176
+ var extraW = borderwidth + outlinewidth;
23177
+
23178
+ g.select('.' + cn.cbbg)
23179
+ .attr('x', (isVertical ? uPx : vPx) - extraW / 2 - (isVertical ? xpad : 0))
23180
+ .attr('y', (isVertical ? vPx : uPx) - (isVertical ? lenPx : ypad + moveY - hColorbarMoveTitle))
23181
+ .attr(isVertical ? 'width' : 'height', Math.max(outerThickness - hColorbarMoveTitle, 2))
23182
+ .attr(isVertical ? 'height' : 'width', Math.max(lenPx + extraW, 2))
23183
+ .call(Color.fill, bgcolor)
23184
+ .call(Color.stroke, opts.bordercolor)
23185
+ .style('stroke-width', borderwidth);
23186
+
23187
+ var moveX = rightSideHorizontal ? Math.max(titleWidth - 10, 0) : 0;
23188
+
23189
+ g.selectAll('.' + cn.cboutline)
23190
+ .attr('x', (isVertical ? uPx : vPx + xpad) + moveX)
23191
+ .attr('y', (isVertical ? vPx + ypad - lenPx : uPx) + (topSideVertical ? titleHeight : 0))
23192
+ .attr(isVertical ? 'width' : 'height', Math.max(thickPx, 2))
23193
+ .attr(isVertical ? 'height' : 'width', Math.max(lenPx - (isVertical ?
23194
+ 2 * ypad + titleHeight :
23195
+ 2 * xpad + moveX
23196
+ ), 2))
23006
23197
  .call(Color.stroke, opts.outlinecolor)
23007
23198
  .style({
23008
23199
  fill: 'none',
23009
- 'stroke-width': opts.outlinewidth
23200
+ 'stroke-width': outlinewidth
23010
23201
  });
23011
23202
 
23012
- // fix positioning for xanchor!='left'
23013
- var xoffset = ({center: 0.5, right: 1}[opts.xanchor] || 0) * outerwidth;
23014
- g.attr('transform', strTranslate(gs.l - xoffset, gs.t));
23203
+ g.attr('transform', strTranslate(
23204
+ gs.l - (isVertical ? xRatio * outerThickness : 0),
23205
+ gs.t - (isVertical ? 0 : (1 - yRatio) * outerThickness - moveY)
23206
+ ));
23207
+
23208
+ if(!isVertical && (
23209
+ borderwidth || (
23210
+ tinycolor(bgcolor).getAlpha() &&
23211
+ !tinycolor.equals(fullLayout.paper_bgcolor, bgcolor)
23212
+ )
23213
+ )) {
23214
+ // for horizontal colorbars when there is a border line or having different background color
23215
+ // hide/adjust x positioning for the first/last tick labels if they go outside the border
23216
+ var tickLabels = axLayer.selectAll('text');
23217
+ var numTicks = tickLabels[0].length;
23218
+
23219
+ var border = g.select('.' + cn.cbbg).node();
23220
+ var oBb = Drawing.bBox(border);
23221
+ var oTr = Drawing.getTranslate(g);
23222
+
23223
+ var TEXTPAD = 2;
23224
+
23225
+ tickLabels.each(function(d, i) {
23226
+ var first = 0;
23227
+ var last = numTicks - 1;
23228
+ if(i === first || i === last) {
23229
+ var iBb = Drawing.bBox(this);
23230
+ var iTr = Drawing.getTranslate(this);
23231
+ var deltaX;
23232
+
23233
+ if(i === last) {
23234
+ var iRight = iBb.right + iTr.x;
23235
+ var oRight = oBb.right + oTr.x + vPx - borderwidth - TEXTPAD + optsX;
23236
+
23237
+ deltaX = oRight - iRight;
23238
+ if(deltaX > 0) deltaX = 0;
23239
+ } else if(i === first) {
23240
+ var iLeft = iBb.left + iTr.x;
23241
+ var oLeft = oBb.left + oTr.x + vPx + borderwidth + TEXTPAD;
23242
+
23243
+ deltaX = oLeft - iLeft;
23244
+ if(deltaX < 0) deltaX = 0;
23245
+ }
23246
+
23247
+ if(deltaX) {
23248
+ if(numTicks < 3) { // adjust position
23249
+ this.setAttribute('transform',
23250
+ 'translate(' + deltaX + ',0) ' +
23251
+ this.getAttribute('transform')
23252
+ );
23253
+ } else { // hide
23254
+ this.setAttribute('visibility', 'hidden');
23255
+ }
23256
+ }
23257
+ }
23258
+ });
23259
+ }
23015
23260
 
23016
23261
  // auto margin adjustment
23017
23262
  var marginOpts = {};
23018
- var tFrac = FROM_TL[opts.yanchor];
23019
- var bFrac = FROM_BR[opts.yanchor];
23020
- if(opts.lenmode === 'pixels') {
23021
- marginOpts.y = opts.y;
23022
- marginOpts.t = outerheight * tFrac;
23023
- marginOpts.b = outerheight * bFrac;
23024
- } else {
23025
- marginOpts.t = marginOpts.b = 0;
23026
- marginOpts.yt = opts.y + opts.len * tFrac;
23027
- marginOpts.yb = opts.y - opts.len * bFrac;
23028
- }
23263
+ var lFrac = FROM_TL[xanchor];
23264
+ var rFrac = FROM_BR[xanchor];
23265
+ var tFrac = FROM_TL[yanchor];
23266
+ var bFrac = FROM_BR[yanchor];
23029
23267
 
23030
- var lFrac = FROM_TL[opts.xanchor];
23031
- var rFrac = FROM_BR[opts.xanchor];
23032
- if(opts.thicknessmode === 'pixels') {
23033
- marginOpts.x = opts.x;
23034
- marginOpts.l = outerwidth * lFrac;
23035
- marginOpts.r = outerwidth * rFrac;
23036
- } else {
23037
- var extraThickness = outerwidth - thickPx;
23038
- marginOpts.l = extraThickness * lFrac;
23039
- marginOpts.r = extraThickness * rFrac;
23040
- marginOpts.xl = opts.x - opts.thickness * lFrac;
23041
- marginOpts.xr = opts.x + opts.thickness * rFrac;
23268
+ var extraThickness = outerThickness - thickPx;
23269
+ if(isVertical) {
23270
+ if(lenmode === 'pixels') {
23271
+ marginOpts.y = optsY;
23272
+ marginOpts.t = lenPx * tFrac;
23273
+ marginOpts.b = lenPx * bFrac;
23274
+ } else {
23275
+ marginOpts.t = marginOpts.b = 0;
23276
+ marginOpts.yt = optsY + len * tFrac;
23277
+ marginOpts.yb = optsY - len * bFrac;
23278
+ }
23279
+
23280
+ if(thicknessmode === 'pixels') {
23281
+ marginOpts.x = optsX;
23282
+ marginOpts.l = outerThickness * lFrac;
23283
+ marginOpts.r = outerThickness * rFrac;
23284
+ } else {
23285
+ marginOpts.l = extraThickness * lFrac;
23286
+ marginOpts.r = extraThickness * rFrac;
23287
+ marginOpts.xl = optsX - thickness * lFrac;
23288
+ marginOpts.xr = optsX + thickness * rFrac;
23289
+ }
23290
+ } else { // horizontal colorbars
23291
+ if(lenmode === 'pixels') {
23292
+ marginOpts.x = optsX;
23293
+ marginOpts.l = lenPx * lFrac;
23294
+ marginOpts.r = lenPx * rFrac;
23295
+ } else {
23296
+ marginOpts.l = marginOpts.r = 0;
23297
+ marginOpts.xl = optsX + len * lFrac;
23298
+ marginOpts.xr = optsX - len * rFrac;
23299
+ }
23300
+
23301
+ if(thicknessmode === 'pixels') {
23302
+ marginOpts.y = 1 - optsY;
23303
+ marginOpts.t = outerThickness * tFrac;
23304
+ marginOpts.b = outerThickness * bFrac;
23305
+ } else {
23306
+ marginOpts.t = extraThickness * tFrac;
23307
+ marginOpts.b = extraThickness * bFrac;
23308
+ marginOpts.yt = optsY - thickness * tFrac;
23309
+ marginOpts.yb = optsY + thickness * bFrac;
23310
+ }
23042
23311
  }
23043
23312
 
23044
23313
  Plots.autoMargin(gd, opts._id, marginOpts);
@@ -23055,6 +23324,7 @@ function drawColorBar(g, opts, gd) {
23055
23324
  }
23056
23325
 
23057
23326
  function makeEditable(g, opts, gd) {
23327
+ var isVertical = opts.orientation === 'v';
23058
23328
  var fullLayout = gd._fullLayout;
23059
23329
  var gs = fullLayout._size;
23060
23330
  var t0, xf, yf;
@@ -23069,9 +23339,13 @@ function makeEditable(g, opts, gd) {
23069
23339
  moveFn: function(dx, dy) {
23070
23340
  g.attr('transform', t0 + strTranslate(dx, dy));
23071
23341
 
23072
- xf = dragElement.align(opts._xLeftFrac + (dx / gs.w), opts._thickFrac,
23342
+ xf = dragElement.align(
23343
+ (isVertical ? opts._uFrac : opts._vFrac) + (dx / gs.w),
23344
+ isVertical ? opts._thickFrac : opts._lenFrac,
23073
23345
  0, 1, opts.xanchor);
23074
- yf = dragElement.align(opts._yBottomFrac - (dy / gs.h), opts._lenFrac,
23346
+ yf = dragElement.align(
23347
+ (isVertical ? opts._vFrac : (1 - opts._uFrac)) - (dy / gs.h),
23348
+ isVertical ? opts._lenFrac : opts._thickFrac,
23075
23349
  0, 1, opts.yanchor);
23076
23350
 
23077
23351
  var csr = dragElement.getCursor(xf, yf, opts.xanchor, opts.yanchor);
@@ -23148,6 +23422,8 @@ function calcLevels(gd, opts, zrange) {
23148
23422
  function mockColorBarAxis(gd, opts, zrange) {
23149
23423
  var fullLayout = gd._fullLayout;
23150
23424
 
23425
+ var isVertical = opts.orientation === 'v';
23426
+
23151
23427
  var cbAxisIn = {
23152
23428
  type: 'linear',
23153
23429
  range: zrange,
@@ -23178,17 +23454,19 @@ function mockColorBarAxis(gd, opts, zrange) {
23178
23454
  title: opts.title,
23179
23455
  showline: true,
23180
23456
  anchor: 'free',
23181
- side: 'right',
23457
+ side: isVertical ? 'right' : 'bottom',
23182
23458
  position: 1
23183
23459
  };
23184
23460
 
23461
+ var letter = isVertical ? 'y' : 'x';
23462
+
23185
23463
  var cbAxisOut = {
23186
23464
  type: 'linear',
23187
- _id: 'y' + opts._id
23465
+ _id: letter + opts._id
23188
23466
  };
23189
23467
 
23190
23468
  var axisOptions = {
23191
- letter: 'y',
23469
+ letter: letter,
23192
23470
  font: fullLayout.font,
23193
23471
  noHover: true,
23194
23472
  noTickson: true,
@@ -25650,7 +25928,7 @@ var TEXTOFFSETSIGN = {
25650
25928
  start: 1, end: -1, middle: 0, bottom: 1, top: -1
25651
25929
  };
25652
25930
 
25653
- function textPointPosition(s, textPosition, fontSize, markerRadius) {
25931
+ function textPointPosition(s, textPosition, fontSize, markerRadius, dontTouchParent) {
25654
25932
  var group = d3.select(s.node().parentNode);
25655
25933
 
25656
25934
  var v = textPosition.indexOf('top') !== -1 ?
@@ -25672,7 +25950,9 @@ function textPointPosition(s, textPosition, fontSize, markerRadius) {
25672
25950
 
25673
25951
  // fix the overall text group position
25674
25952
  s.attr('text-anchor', h);
25675
- group.attr('transform', strTranslate(dx, dy));
25953
+ if(!dontTouchParent) {
25954
+ group.attr('transform', strTranslate(dx, dy));
25955
+ }
25676
25956
  }
25677
25957
 
25678
25958
  function extracTextFontSize(d, trace) {
@@ -25742,7 +26022,8 @@ drawing.selectedTextStyle = function(s, trace) {
25742
26022
  var fontSize = extracTextFontSize(d, trace);
25743
26023
 
25744
26024
  Color.fill(tx, tc);
25745
- textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc);
26025
+ var dontTouchParent = Registry.traceIs(trace, 'bar-like');
26026
+ textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc, dontTouchParent);
25746
26027
  });
25747
26028
  };
25748
26029
 
@@ -27773,11 +28054,13 @@ var cartesianScatterPoints = {
27773
28054
  // The actual rendering is done by private function _hover.
27774
28055
  exports.hover = function hover(gd, evt, subplot, noHoverEvent) {
27775
28056
  gd = Lib.getGraphDiv(gd);
27776
-
28057
+ // The 'target' property changes when bubbling out of Shadow DOM.
28058
+ // Throttling can delay reading the target, so we save the current value.
28059
+ var eventTarget = evt.target;
27777
28060
  Lib.throttle(
27778
28061
  gd._fullLayout._uid + constants.HOVERID,
27779
28062
  constants.HOVERMINTIME,
27780
- function() { _hover(gd, evt, subplot, noHoverEvent); }
28063
+ function() { _hover(gd, evt, subplot, noHoverEvent, eventTarget); }
27781
28064
  );
27782
28065
  };
27783
28066
 
@@ -27942,7 +28225,7 @@ exports.loneHover = function loneHover(hoverItems, opts) {
27942
28225
  };
27943
28226
 
27944
28227
  // The actual implementation is here:
27945
- function _hover(gd, evt, subplot, noHoverEvent) {
28228
+ function _hover(gd, evt, subplot, noHoverEvent, eventTarget) {
27946
28229
  if(!subplot) subplot = 'xy';
27947
28230
 
27948
28231
  // if the user passed in an array of subplots,
@@ -28061,7 +28344,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
28061
28344
  // [x|y]px: the pixels (from top left) of the mouse location
28062
28345
  // on the currently selected plot area
28063
28346
  // add pointerX|Y property for drawing the spikes in spikesnap 'cursor' situation
28064
- var hasUserCalledHover = !evt.target;
28347
+ var hasUserCalledHover = !eventTarget;
28065
28348
  var xpx, ypx;
28066
28349
 
28067
28350
  if(hasUserCalledHover) {
@@ -28078,13 +28361,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
28078
28361
  return;
28079
28362
  }
28080
28363
 
28081
- // Discover event target, traversing open shadow roots.
28082
- var target = evt.composedPath && evt.composedPath()[0];
28083
- if(!target) {
28084
- // Fallback for browsers not supporting composedPath
28085
- target = evt.target;
28086
- }
28087
- var dbb = target.getBoundingClientRect();
28364
+ var dbb = eventTarget.getBoundingClientRect();
28088
28365
 
28089
28366
  xpx = evt.clientX - dbb.left;
28090
28367
  ypx = evt.clientY - dbb.top;
@@ -28532,15 +28809,15 @@ function _hover(gd, evt, subplot, noHoverEvent) {
28532
28809
  if(!helpers.isUnifiedHover(hovermode)) {
28533
28810
  hoverAvoidOverlaps(hoverLabels, rotateLabels ? 'xa' : 'ya', fullLayout);
28534
28811
  alignHoverText(hoverLabels, rotateLabels, fullLayout._invScaleX, fullLayout._invScaleY);
28535
- } // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true
28812
+ } // TODO: tagName hack is needed to appease geo.js's hack of using eventTarget=true
28536
28813
  // we should improve the "fx" API so other plots can use it without these hack.
28537
- if(evt.target && evt.target.tagName) {
28814
+ if(eventTarget && eventTarget.tagName) {
28538
28815
  var hasClickToShow = Registry.getComponentMethod('annotations', 'hasClickToShow')(gd, newhoverdata);
28539
- overrideCursor(d3.select(evt.target), hasClickToShow ? 'pointer' : '');
28816
+ overrideCursor(d3.select(eventTarget), hasClickToShow ? 'pointer' : '');
28540
28817
  }
28541
28818
 
28542
28819
  // don't emit events if called manually
28543
- if(!evt.target || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
28820
+ if(!eventTarget || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
28544
28821
 
28545
28822
  if(oldhoverdata) {
28546
28823
  gd.emit('plotly_unhover', {
@@ -28802,7 +29079,9 @@ function createHoverText(hoverData, opts) {
28802
29079
  orientation: 'v'
28803
29080
  }
28804
29081
  };
28805
- var mockLayoutOut = {};
29082
+ var mockLayoutOut = {
29083
+ font: font
29084
+ };
28806
29085
  legendSupplyDefaults(mockLayoutIn, mockLayoutOut, gd._fullData);
28807
29086
  var mockLegend = mockLayoutOut.legend;
28808
29087
 
@@ -28843,7 +29122,8 @@ function createHoverText(hoverData, opts) {
28843
29122
 
28844
29123
  // Draw unified hover label
28845
29124
  mockLegend._inHover = true;
28846
- mockLegend._groupTitleFont = font;
29125
+ mockLegend._groupTitleFont = hoverlabel.grouptitlefont;
29126
+
28847
29127
  legendDraw(gd, mockLegend);
28848
29128
 
28849
29129
  // Position the hover
@@ -29845,9 +30125,11 @@ var isUnifiedHover = _dereq_('./helpers').isUnifiedHover;
29845
30125
  module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts) {
29846
30126
  opts = opts || {};
29847
30127
 
30128
+ var hasLegend = contOut.legend;
30129
+
29848
30130
  function inheritFontAttr(attr) {
29849
30131
  if(!opts.font[attr]) {
29850
- opts.font[attr] = contOut.legend ? contOut.legend.font[attr] : contOut.font[attr];
30132
+ opts.font[attr] = hasLegend ? contOut.legend.font[attr] : contOut.font[attr];
29851
30133
  }
29852
30134
  }
29853
30135
 
@@ -29858,7 +30140,7 @@ module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts
29858
30140
  inheritFontAttr('family');
29859
30141
  inheritFontAttr('color');
29860
30142
 
29861
- if(contOut.legend) {
30143
+ if(hasLegend) {
29862
30144
  if(!opts.bgcolor) opts.bgcolor = Color.combine(contOut.legend.bgcolor, contOut.paper_bgcolor);
29863
30145
  if(!opts.bordercolor) opts.bordercolor = contOut.legend.bordercolor;
29864
30146
  } else {
@@ -29967,11 +30249,13 @@ function castHoverinfo(trace, fullLayout, ptNumber) {
29967
30249
 
29968
30250
  var constants = _dereq_('./constants');
29969
30251
 
29970
- var fontAttrs = _dereq_('../../plots/font_attributes')({
30252
+ var fontAttrs = _dereq_('../../plots/font_attributes');
30253
+
30254
+ var font = fontAttrs({
29971
30255
  editType: 'none',
29972
30256
  });
29973
- fontAttrs.family.dflt = constants.HOVERFONT;
29974
- fontAttrs.size.dflt = constants.HOVERFONTSIZE;
30257
+ font.family.dflt = constants.HOVERFONT;
30258
+ font.size.dflt = constants.HOVERFONTSIZE;
29975
30259
 
29976
30260
  module.exports = {
29977
30261
  clickmode: {
@@ -30027,7 +30311,10 @@ module.exports = {
30027
30311
  valType: 'color',
30028
30312
  editType: 'none',
30029
30313
  },
30030
- font: fontAttrs,
30314
+ font: font,
30315
+ grouptitlefont: fontAttrs({
30316
+ editType: 'none',
30317
+ }),
30031
30318
  align: {
30032
30319
  valType: 'enumerated',
30033
30320
  values: ['left', 'right', 'auto'],
@@ -30040,6 +30327,7 @@ module.exports = {
30040
30327
  dflt: 15,
30041
30328
  editType: 'none',
30042
30329
  },
30330
+
30043
30331
  editType: 'none'
30044
30332
  },
30045
30333
  selectdirection: {
@@ -30087,6 +30375,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
30087
30375
  }
30088
30376
 
30089
30377
  handleHoverLabelDefaults(layoutIn, layoutOut, coerce);
30378
+
30379
+ Lib.coerceFont(coerce, 'hoverlabel.grouptitlefont', layoutOut.hoverlabel.font);
30090
30380
  };
30091
30381
 
30092
30382
  },{"../../lib":252,"./hoverlabel_defaults":157,"./hovermode_defaults":158,"./layout_attributes":160}],162:[function(_dereq_,module,exports){
@@ -30970,6 +31260,9 @@ module.exports = {
30970
31260
  font: fontAttrs({
30971
31261
  editType: 'legend',
30972
31262
  }),
31263
+ grouptitlefont: fontAttrs({
31264
+ editType: 'legend',
31265
+ }),
30973
31266
  orientation: {
30974
31267
  valType: 'enumerated',
30975
31268
  values: ['v', 'h'],
@@ -31093,6 +31386,7 @@ var Registry = _dereq_('../../registry');
31093
31386
  var Lib = _dereq_('../../lib');
31094
31387
  var Template = _dereq_('../../plot_api/plot_template');
31095
31388
 
31389
+ var plotsAttrs = _dereq_('../../plots/attributes');
31096
31390
  var attributes = _dereq_('./attributes');
31097
31391
  var basePlotLayoutAttributes = _dereq_('../../plots/layout_attributes');
31098
31392
  var helpers = _dereq_('./helpers');
@@ -31100,13 +31394,30 @@ var helpers = _dereq_('./helpers');
31100
31394
 
31101
31395
  module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
31102
31396
  var containerIn = layoutIn.legend || {};
31397
+ var containerOut = Template.newContainer(layoutOut, 'legend');
31398
+
31399
+ function coerce(attr, dflt) {
31400
+ return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
31401
+ }
31402
+
31403
+ var trace;
31404
+ var traceCoerce = function(attr, dflt) {
31405
+ var traceIn = trace._input;
31406
+ var traceOut = trace;
31407
+ return Lib.coerce(traceIn, traceOut, plotsAttrs, attr, dflt);
31408
+ };
31409
+
31410
+ var globalFont = layoutOut.font || {};
31411
+ var grouptitlefont = Lib.coerceFont(coerce, 'grouptitlefont', Lib.extendFlat({}, globalFont, {
31412
+ size: Math.round(globalFont.size * 1.1)
31413
+ }));
31103
31414
 
31104
31415
  var legendTraceCount = 0;
31105
31416
  var legendReallyHasATrace = false;
31106
31417
  var defaultOrder = 'normal';
31107
31418
 
31108
31419
  for(var i = 0; i < fullData.length; i++) {
31109
- var trace = fullData[i];
31420
+ trace = fullData[i];
31110
31421
 
31111
31422
  if(!trace.visible) continue;
31112
31423
 
@@ -31133,6 +31444,8 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
31133
31444
  legendTraceCount++;
31134
31445
  }
31135
31446
  }
31447
+
31448
+ Lib.coerceFont(traceCoerce, 'legendgrouptitle.font', grouptitlefont);
31136
31449
  }
31137
31450
 
31138
31451
  if((Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
@@ -31151,13 +31464,10 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
31151
31464
  basePlotLayoutAttributes, 'showlegend',
31152
31465
  legendReallyHasATrace && legendTraceCount > 1);
31153
31466
 
31154
- if(showLegend === false && !containerIn.uirevision) return;
31155
-
31156
- var containerOut = Template.newContainer(layoutOut, 'legend');
31467
+ // delete legend
31468
+ if(showLegend === false) layoutOut.legend = undefined;
31157
31469
 
31158
- function coerce(attr, dflt) {
31159
- return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
31160
- }
31470
+ if(showLegend === false && !containerIn.uirevision) return;
31161
31471
 
31162
31472
  coerce('uirevision', layoutOut.uirevision);
31163
31473
 
@@ -31219,7 +31529,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
31219
31529
  }
31220
31530
  };
31221
31531
 
31222
- },{"../../lib":252,"../../plot_api/plot_template":290,"../../plots/layout_attributes":347,"../../registry":352,"./attributes":169,"./helpers":175}],172:[function(_dereq_,module,exports){
31532
+ },{"../../lib":252,"../../plot_api/plot_template":290,"../../plots/attributes":297,"../../plots/layout_attributes":347,"../../registry":352,"./attributes":169,"./helpers":175}],172:[function(_dereq_,module,exports){
31223
31533
  'use strict';
31224
31534
 
31225
31535
  var d3 = _dereq_('@plotly/d3');
@@ -39671,8 +39981,10 @@ function draw(gd, titleClass, options) {
39671
39981
 
39672
39982
  var elShouldExist = txt || editable;
39673
39983
 
39984
+ var hColorbarMoveTitle;
39674
39985
  if(!group) {
39675
39986
  group = Lib.ensureSingle(fullLayout._infolayer, 'g', 'g-' + titleClass);
39987
+ hColorbarMoveTitle = fullLayout._hColorbarMoveTitle;
39676
39988
  }
39677
39989
 
39678
39990
  var el = group.selectAll('text')
@@ -39696,13 +40008,17 @@ function draw(gd, titleClass, options) {
39696
40008
  function drawTitle(titleEl) {
39697
40009
  var transformVal;
39698
40010
 
40011
+ if(!transform && hColorbarMoveTitle) {
40012
+ transform = {};
40013
+ }
40014
+
39699
40015
  if(transform) {
39700
40016
  transformVal = '';
39701
40017
  if(transform.rotate) {
39702
40018
  transformVal += 'rotate(' + [transform.rotate, attributes.x, attributes.y] + ')';
39703
40019
  }
39704
- if(transform.offset) {
39705
- transformVal += strTranslate(0, transform.offset);
40020
+ if(transform.offset || hColorbarMoveTitle) {
40021
+ transformVal += strTranslate(0, (transform.offset || 0) - (hColorbarMoveTitle || 0));
39706
40022
  }
39707
40023
  } else {
39708
40024
  transformVal = null;
@@ -51346,7 +51662,7 @@ function cleanDeprecatedAttributeKeys(aobj) {
51346
51662
  if((key === 'title' || oldAxisTitleRegex.test(key) || colorbarRegex.test(key)) &&
51347
51663
  (typeof value === 'string' || typeof value === 'number')) {
51348
51664
  replace(key, key.replace('title', 'title.text'));
51349
- } else if(key.indexOf('titlefont') > -1) {
51665
+ } else if(key.indexOf('titlefont') > -1 && key.indexOf('grouptitlefont') === -1) {
51350
51666
  replace(key, key.replace('titlefont', 'title.font'));
51351
51667
  } else if(key.indexOf('titleposition') > -1) {
51352
51668
  replace(key, key.replace('titleposition', 'title.position'));
@@ -52023,7 +52339,8 @@ function findUIPattern(key, patternSpecs) {
52023
52339
  var spec = patternSpecs[i];
52024
52340
  var match = key.match(spec.pattern);
52025
52341
  if(match) {
52026
- return {head: match[1], attr: spec.attr};
52342
+ var head = match[1] || '';
52343
+ return {head: head, tail: key.substr(head.length + 1), attr: spec.attr};
52027
52344
  }
52028
52345
  }
52029
52346
  }
@@ -52075,26 +52392,54 @@ function valsMatch(v1, v2) {
52075
52392
 
52076
52393
  function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
52077
52394
  var layoutPreGUI = oldFullLayout._preGUI;
52078
- var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal;
52395
+ var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal, head, tail;
52079
52396
  var bothInheritAutorange = [];
52397
+ var newAutorangeIn = {};
52080
52398
  var newRangeAccepted = {};
52081
52399
  for(key in layoutPreGUI) {
52082
52400
  match = findUIPattern(key, layoutUIControlPatterns);
52083
52401
  if(match) {
52084
- revAttr = match.attr || (match.head + '.uirevision');
52402
+ head = match.head;
52403
+ tail = match.tail;
52404
+ revAttr = match.attr || (head + '.uirevision');
52085
52405
  oldRev = nestedProperty(oldFullLayout, revAttr).get();
52086
52406
  newRev = oldRev && getNewRev(revAttr, layout);
52407
+
52087
52408
  if(newRev && (newRev === oldRev)) {
52088
52409
  preGUIVal = layoutPreGUI[key];
52089
52410
  if(preGUIVal === null) preGUIVal = undefined;
52090
52411
  newNP = nestedProperty(layout, key);
52091
52412
  newVal = newNP.get();
52413
+
52092
52414
  if(valsMatch(newVal, preGUIVal)) {
52093
- if(newVal === undefined && key.substr(key.length - 9) === 'autorange') {
52094
- bothInheritAutorange.push(key.substr(0, key.length - 10));
52415
+ if(newVal === undefined && tail === 'autorange') {
52416
+ bothInheritAutorange.push(head);
52095
52417
  }
52096
52418
  newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
52097
52419
  continue;
52420
+ } else if(tail === 'autorange' || tail.substr(0, 6) === 'range[') {
52421
+ // Special case for (auto)range since we push it back into the layout
52422
+ // so all null should be treated equivalently to autorange: true with any range
52423
+ var pre0 = layoutPreGUI[head + '.range[0]'];
52424
+ var pre1 = layoutPreGUI[head + '.range[1]'];
52425
+ var preAuto = layoutPreGUI[head + '.autorange'];
52426
+ if(preAuto || (preAuto === null && pre0 === null && pre1 === null)) {
52427
+ // Only read the input layout once and stash the result,
52428
+ // so we get it before we start modifying it
52429
+ if(!(head in newAutorangeIn)) {
52430
+ var newContainer = nestedProperty(layout, head).get();
52431
+ newAutorangeIn[head] = newContainer && (
52432
+ newContainer.autorange ||
52433
+ (newContainer.autorange !== false && (
52434
+ !newContainer.range || newContainer.range.length !== 2)
52435
+ )
52436
+ );
52437
+ }
52438
+ if(newAutorangeIn[head]) {
52439
+ newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
52440
+ continue;
52441
+ }
52442
+ }
52098
52443
  }
52099
52444
  }
52100
52445
  } else {
@@ -52105,12 +52450,12 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
52105
52450
  // so remove it from _preGUI for next time.
52106
52451
  delete layoutPreGUI[key];
52107
52452
 
52108
- if(key.substr(key.length - 8, 6) === 'range[') {
52109
- newRangeAccepted[key.substr(0, key.length - 9)] = 1;
52453
+ if(match && match.tail.substr(0, 6) === 'range[') {
52454
+ newRangeAccepted[match.head] = 1;
52110
52455
  }
52111
52456
  }
52112
52457
 
52113
- // Special logic for `autorange`, since it interacts with `range`:
52458
+ // More special logic for `autorange`, since it interacts with `range`:
52114
52459
  // If the new figure's matching `range` was kept, and `autorange`
52115
52460
  // wasn't supplied explicitly in either the original or the new figure,
52116
52461
  // we shouldn't alter that - but we may just have done that, so fix it.
@@ -69185,6 +69530,9 @@ module.exports = function(opts) {
69185
69530
  // TODO - that's uber hacky... better solution?
69186
69531
  };
69187
69532
 
69533
+ if(opts.autoSize) attrs.size.dflt = 'auto';
69534
+ if(opts.autoColor) attrs.color.dflt = 'auto';
69535
+
69188
69536
  if(opts.arrayOk) {
69189
69537
  attrs.family.arrayOk = true;
69190
69538
  attrs.size.arrayOk = true;
@@ -71579,6 +71927,7 @@ module.exports = {
71579
71927
  valType: 'boolean',
71580
71928
  editType: 'legend',
71581
71929
  },
71930
+
71582
71931
  colorway: {
71583
71932
  valType: 'colorlist',
71584
71933
  dflt: colorAttrs.defaults,
@@ -72991,13 +73340,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
72991
73340
  );
72992
73341
 
72993
73342
  coerce('legendgroup');
72994
- var titleText = coerce('legendgrouptitle.text');
72995
- if(titleText) {
72996
- Lib.coerceFont(coerce, 'legendgrouptitle.font', Lib.extendFlat({}, layout.font, {
72997
- size: Math.round(layout.font.size * 1.1) // default to larger font size
72998
- }));
72999
- }
73000
-
73343
+ coerce('legendgrouptitle.text');
73001
73344
  coerce('legendrank');
73002
73345
 
73003
73346
  traceOut._dfltShowLegend = true;
@@ -73145,16 +73488,14 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {
73145
73488
 
73146
73489
  coerce('autotypenumbers');
73147
73490
 
73148
- var globalFont = Lib.coerceFont(coerce, 'font');
73149
-
73150
- coerce('title.text', layoutOut._dfltTitle.plot);
73491
+ var font = Lib.coerceFont(coerce, 'font');
73492
+ var fontSize = font.size;
73151
73493
 
73152
- Lib.coerceFont(coerce, 'title.font', {
73153
- family: globalFont.family,
73154
- size: Math.round(globalFont.size * 1.4),
73155
- color: globalFont.color
73156
- });
73494
+ Lib.coerceFont(coerce, 'title.font', Lib.extendFlat({}, font, {
73495
+ size: Math.round(fontSize * 1.4)
73496
+ }));
73157
73497
 
73498
+ coerce('title.text', layoutOut._dfltTitle.plot);
73158
73499
  coerce('title.xref');
73159
73500
  coerce('title.yref');
73160
73501
  coerce('title.x');
@@ -85944,7 +86285,7 @@ function getSortFunc(opts, d2c) {
85944
86285
  'use strict';
85945
86286
 
85946
86287
  // package version injected by `npm run preprocess`
85947
- exports.version = '2.6.2';
86288
+ exports.version = '2.8.0';
85948
86289
 
85949
86290
  },{}],435:[function(_dereq_,module,exports){
85950
86291
  (function (global){(function (){