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 (basic) v2.6.2
2
+ * plotly.js (basic) v2.8.0
3
3
  * Copyright 2012-2021, Plotly, Inc.
4
4
  * All rights reserved.
5
5
  * Licensed under the MIT license
@@ -21564,13 +21564,11 @@ var overrideAll = _dereq_('../../plot_api/edit_types').overrideAll;
21564
21564
 
21565
21565
 
21566
21566
  module.exports = overrideAll({
21567
- // TODO: only right is supported currently
21568
- // orient: {
21569
- // valType: 'enumerated',
21570
- // values: ['left', 'right', 'top', 'bottom'],
21571
- // dflt: 'right',
21572
- //
21573
- // },
21567
+ orientation: {
21568
+ valType: 'enumerated',
21569
+ values: ['h', 'v'],
21570
+ dflt: 'v',
21571
+ },
21574
21572
  thicknessmode: {
21575
21573
  valType: 'enumerated',
21576
21574
  values: ['fraction', 'pixels'],
@@ -21593,14 +21591,12 @@ module.exports = overrideAll({
21593
21591
  },
21594
21592
  x: {
21595
21593
  valType: 'number',
21596
- dflt: 1.02,
21597
21594
  min: -2,
21598
21595
  max: 3,
21599
21596
  },
21600
21597
  xanchor: {
21601
21598
  valType: 'enumerated',
21602
21599
  values: ['left', 'center', 'right'],
21603
- dflt: 'left',
21604
21600
  },
21605
21601
  xpad: {
21606
21602
  valType: 'number',
@@ -21609,14 +21605,12 @@ module.exports = overrideAll({
21609
21605
  },
21610
21606
  y: {
21611
21607
  valType: 'number',
21612
- dflt: 0.5,
21613
21608
  min: -2,
21614
21609
  max: 3,
21615
21610
  },
21616
21611
  yanchor: {
21617
21612
  valType: 'enumerated',
21618
21613
  values: ['top', 'middle', 'bottom'],
21619
- dflt: 'middle',
21620
21614
  },
21621
21615
  ypad: {
21622
21616
  valType: 'number',
@@ -21648,15 +21642,21 @@ module.exports = overrideAll({
21648
21642
  ticks: extendFlat({}, axesAttrs.ticks, {dflt: ''}),
21649
21643
  ticklabeloverflow: extendFlat({}, axesAttrs.ticklabeloverflow, {
21650
21644
  }),
21645
+
21646
+ // ticklabelposition: not used directly, as values depend on orientation
21647
+ // left/right options are for x axes, and top/bottom options are for y axes
21651
21648
  ticklabelposition: {
21652
21649
  valType: 'enumerated',
21653
21650
  values: [
21654
21651
  'outside', 'inside',
21655
21652
  'outside top', 'inside top',
21653
+ 'outside left', 'inside left',
21654
+ 'outside right', 'inside right',
21656
21655
  'outside bottom', 'inside bottom'
21657
21656
  ],
21658
21657
  dflt: 'outside',
21659
21658
  },
21659
+
21660
21660
  ticklen: axesAttrs.ticklen,
21661
21661
  tickwidth: axesAttrs.tickwidth,
21662
21662
  tickcolor: axesAttrs.tickcolor,
@@ -21683,7 +21683,6 @@ module.exports = overrideAll({
21683
21683
  side: {
21684
21684
  valType: 'enumerated',
21685
21685
  values: ['right', 'top', 'bottom'],
21686
- dflt: 'top',
21687
21686
  }
21688
21687
  },
21689
21688
 
@@ -21742,23 +21741,30 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
21742
21741
  return Lib.coerce(colorbarIn, colorbarOut, attributes, attr, dflt);
21743
21742
  }
21744
21743
 
21744
+ var margin = layout.margin || {t: 0, b: 0, l: 0, r: 0};
21745
+ var w = layout.width - margin.l - margin.r;
21746
+ var h = layout.height - margin.t - margin.b;
21747
+
21748
+ var orientation = coerce('orientation');
21749
+ var isVertical = orientation === 'v';
21750
+
21745
21751
  var thicknessmode = coerce('thicknessmode');
21746
21752
  coerce('thickness', (thicknessmode === 'fraction') ?
21747
- 30 / (layout.width - layout.margin.l - layout.margin.r) :
21753
+ 30 / (isVertical ? w : h) :
21748
21754
  30
21749
21755
  );
21750
21756
 
21751
21757
  var lenmode = coerce('lenmode');
21752
21758
  coerce('len', (lenmode === 'fraction') ?
21753
21759
  1 :
21754
- layout.height - layout.margin.t - layout.margin.b
21760
+ isVertical ? h : w
21755
21761
  );
21756
21762
 
21757
- coerce('x');
21758
- coerce('xanchor');
21763
+ coerce('x', isVertical ? 1.02 : 0.5);
21764
+ coerce('xanchor', isVertical ? 'left' : 'center');
21759
21765
  coerce('xpad');
21760
- coerce('y');
21761
- coerce('yanchor');
21766
+ coerce('y', isVertical ? 0.5 : 1.02);
21767
+ coerce('yanchor', isVertical ? 'middle' : 'bottom');
21762
21768
  coerce('ypad');
21763
21769
  Lib.noneOrAll(colorbarIn, colorbarOut, ['x', 'y']);
21764
21770
 
@@ -21768,7 +21774,22 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
21768
21774
  coerce('borderwidth');
21769
21775
  coerce('bgcolor');
21770
21776
 
21771
- var ticklabelposition = coerce('ticklabelposition');
21777
+ var ticklabelposition = Lib.coerce(colorbarIn, colorbarOut, {
21778
+ ticklabelposition: {
21779
+ valType: 'enumerated',
21780
+ dflt: 'outside',
21781
+ values: isVertical ? [
21782
+ 'outside', 'inside',
21783
+ 'outside top', 'inside top',
21784
+ 'outside bottom', 'inside bottom'
21785
+ ] : [
21786
+ 'outside', 'inside',
21787
+ 'outside left', 'inside left',
21788
+ 'outside right', 'inside right'
21789
+ ]
21790
+ }
21791
+ }, 'ticklabelposition');
21792
+
21772
21793
  coerce('ticklabeloverflow', ticklabelposition.indexOf('inside') !== -1 ? 'hide past domain' : 'hide past div');
21773
21794
 
21774
21795
  handleTickValueDefaults(colorbarIn, colorbarOut, coerce, 'linear');
@@ -21790,7 +21811,7 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
21790
21811
  size: Lib.bigFont(tickFont.size)
21791
21812
  });
21792
21813
  Lib.coerceFont(coerce, 'title.font', dfltTitleFont);
21793
- coerce('title.side');
21814
+ coerce('title.side', isVertical ? 'top' : 'right');
21794
21815
  };
21795
21816
 
21796
21817
  },{"../../lib":232,"../../plot_api/plot_template":268,"../../plots/cartesian/prefix_suffix_defaults":298,"../../plots/cartesian/tick_label_defaults":303,"../../plots/cartesian/tick_mark_defaults":304,"../../plots/cartesian/tick_value_defaults":305,"./attributes":103}],106:[function(_dereq_,module,exports){
@@ -21963,6 +21984,21 @@ function makeColorBarData(gd) {
21963
21984
  }
21964
21985
 
21965
21986
  function drawColorBar(g, opts, gd) {
21987
+ var isVertical = opts.orientation === 'v';
21988
+ var len = opts.len;
21989
+ var lenmode = opts.lenmode;
21990
+ var thickness = opts.thickness;
21991
+ var thicknessmode = opts.thicknessmode;
21992
+ var outlinewidth = opts.outlinewidth;
21993
+ var borderwidth = opts.borderwidth;
21994
+ var bgcolor = opts.bgcolor;
21995
+ var xanchor = opts.xanchor;
21996
+ var yanchor = opts.yanchor;
21997
+ var xpad = opts.xpad;
21998
+ var ypad = opts.ypad;
21999
+ var optsX = opts.x;
22000
+ var optsY = isVertical ? opts.y : 1 - opts.y;
22001
+
21966
22002
  var fullLayout = gd._fullLayout;
21967
22003
  var gs = fullLayout._size;
21968
22004
 
@@ -21992,42 +22028,64 @@ function drawColorBar(g, opts, gd) {
21992
22028
  // when the colorbar itself is pushing the margins.
21993
22029
  // but then the fractional size is calculated based on the
21994
22030
  // actual graph size, so that the axes will size correctly.
21995
- var thickPx = Math.round(opts.thickness * (opts.thicknessmode === 'fraction' ? gs.w : 1));
21996
- var thickFrac = thickPx / gs.w;
21997
- var lenPx = Math.round(opts.len * (opts.lenmode === 'fraction' ? gs.h : 1));
21998
- var lenFrac = lenPx / gs.h;
21999
- var xpadFrac = opts.xpad / gs.w;
22000
- var yExtraPx = (opts.borderwidth + opts.outlinewidth) / 2;
22001
- var ypadFrac = opts.ypad / gs.h;
22031
+ var thickPx = Math.round(thickness * (thicknessmode === 'fraction' ? (isVertical ? gs.w : gs.h) : 1));
22032
+ var thickFrac = thickPx / (isVertical ? gs.w : gs.h);
22033
+ var lenPx = Math.round(len * (lenmode === 'fraction' ? (isVertical ? gs.h : gs.w) : 1));
22034
+ var lenFrac = lenPx / (isVertical ? gs.h : gs.w);
22002
22035
 
22003
22036
  // x positioning: do it initially just for left anchor,
22004
22037
  // then fix at the end (since we don't know the width yet)
22005
- var xLeft = Math.round(opts.x * gs.w + opts.xpad);
22006
- // for dragging... this is getting a little muddled...
22007
- var xLeftFrac = opts.x - thickFrac * ({center: 0.5, right: 1}[opts.xanchor] || 0);
22038
+ var uPx = Math.round(isVertical ?
22039
+ optsX * gs.w + xpad :
22040
+ optsY * gs.h + ypad
22041
+ );
22008
22042
 
22009
- // y positioning we can do correctly from the start
22010
- var yBottomFrac = opts.y + lenFrac * (({top: -0.5, bottom: 0.5}[opts.yanchor] || 0) - 0.5);
22011
- var yBottomPx = Math.round(gs.h * (1 - yBottomFrac));
22012
- var yTopPx = yBottomPx - lenPx;
22043
+ var xRatio = {center: 0.5, right: 1}[xanchor] || 0;
22044
+ var yRatio = {top: 1, middle: 0.5}[yanchor] || 0;
22045
+
22046
+ // for dragging... this is getting a little muddled...
22047
+ var uFrac = isVertical ?
22048
+ optsX - xRatio * thickFrac :
22049
+ optsY - yRatio * thickFrac;
22050
+
22051
+ // y/x positioning (for v/h) we can do correctly from the start
22052
+ var vFrac = isVertical ?
22053
+ optsY - yRatio * lenFrac :
22054
+ optsX - xRatio * lenFrac;
22055
+
22056
+ var vPx = Math.round(isVertical ?
22057
+ gs.h * (1 - vFrac) :
22058
+ gs.w * vFrac
22059
+ );
22013
22060
 
22014
22061
  // stash a few things for makeEditable
22015
22062
  opts._lenFrac = lenFrac;
22016
22063
  opts._thickFrac = thickFrac;
22017
- opts._xLeftFrac = xLeftFrac;
22018
- opts._yBottomFrac = yBottomFrac;
22064
+ opts._uFrac = uFrac;
22065
+ opts._vFrac = vFrac;
22019
22066
 
22020
22067
  // stash mocked axis for contour label formatting
22021
22068
  var ax = opts._axis = mockColorBarAxis(gd, opts, zrange);
22022
22069
 
22023
22070
  // position can't go in through supplyDefaults
22024
22071
  // because that restricts it to [0,1]
22025
- ax.position = opts.x + xpadFrac + thickFrac;
22072
+ ax.position = thickFrac + (isVertical ?
22073
+ optsX + xpad / gs.w :
22074
+ optsY + ypad / gs.h
22075
+ );
22076
+
22077
+ var topOrBottom = ['top', 'bottom'].indexOf(titleSide) !== -1;
22078
+
22079
+ if(isVertical && topOrBottom) {
22080
+ ax.title.side = titleSide;
22081
+ ax.titlex = optsX + xpad / gs.w;
22082
+ ax.titley = vFrac + (title.side === 'top' ? lenFrac - ypad / gs.h : ypad / gs.h);
22083
+ }
22026
22084
 
22027
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22085
+ if(!isVertical && !topOrBottom) {
22028
22086
  ax.title.side = titleSide;
22029
- ax.titlex = opts.x + xpadFrac;
22030
- ax.titley = yBottomFrac + (title.side === 'top' ? lenFrac - ypadFrac : ypadFrac);
22087
+ ax.titley = optsY + ypad / gs.h;
22088
+ ax.titlex = vFrac + xpad / gs.w; // right side
22031
22089
  }
22032
22090
 
22033
22091
  if(line.color && opts.tickmode === 'auto') {
@@ -22035,7 +22093,7 @@ function drawColorBar(g, opts, gd) {
22035
22093
  ax.tick0 = levelsIn.start;
22036
22094
  var dtick = levelsIn.size;
22037
22095
  // expand if too many contours, so we don't get too many ticks
22038
- var autoNtick = Lib.constrain((yBottomPx - yTopPx) / 50, 4, 15) + 1;
22096
+ var autoNtick = Lib.constrain(lenPx / 50, 4, 15) + 1;
22039
22097
  var dtFactor = (zrange[1] - zrange[0]) / ((opts.nticks || autoNtick) * dtick);
22040
22098
  if(dtFactor > 1) {
22041
22099
  var dtexp = Math.pow(10, Math.floor(Math.log(dtFactor) / Math.LN10));
@@ -22052,9 +22110,12 @@ function drawColorBar(g, opts, gd) {
22052
22110
 
22053
22111
  // set domain after init, because we may want to
22054
22112
  // allow it outside [0,1]
22055
- ax.domain = [
22056
- yBottomFrac + ypadFrac,
22057
- yBottomFrac + lenFrac - ypadFrac
22113
+ ax.domain = isVertical ? [
22114
+ vFrac + ypad / gs.h,
22115
+ vFrac + lenFrac - ypad / gs.h
22116
+ ] : [
22117
+ vFrac + xpad / gs.w,
22118
+ vFrac + lenFrac - xpad / gs.w
22058
22119
  ];
22059
22120
 
22060
22121
  ax.setScale();
@@ -22064,9 +22125,13 @@ function drawColorBar(g, opts, gd) {
22064
22125
  var titleCont = g.select('.' + cn.cbtitleunshift)
22065
22126
  .attr('transform', strTranslate(-Math.round(gs.l), -Math.round(gs.t)));
22066
22127
 
22128
+ var ticklabelposition = ax.ticklabelposition;
22129
+ var titleFontSize = ax.title.font.size;
22130
+
22067
22131
  var axLayer = g.select('.' + cn.cbaxis);
22068
22132
  var titleEl;
22069
22133
  var titleHeight = 0;
22134
+ var titleWidth = 0;
22070
22135
 
22071
22136
  function drawTitle(titleClass, titleOpts) {
22072
22137
  var dfltTitleOpts = {
@@ -22091,58 +22156,102 @@ function drawColorBar(g, opts, gd) {
22091
22156
  }
22092
22157
 
22093
22158
  function drawDummyTitle() {
22094
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22095
- // draw the title so we know how much room it needs
22096
- // when we squish the axis. This one only applies to
22097
- // top or bottom titles, not right side.
22098
- var x = gs.l + (opts.x + xpadFrac) * gs.w;
22099
- var fontSize = ax.title.font.size;
22100
- var y;
22159
+ // draw the title so we know how much room it needs
22160
+ // when we squish the axis.
22161
+ // On vertical colorbars this only applies to top or bottom titles, not right side.
22162
+ // On horizontal colorbars this only applies to right, etc.
22163
+
22164
+ if(
22165
+ (isVertical && topOrBottom) ||
22166
+ (!isVertical && !topOrBottom)
22167
+ ) {
22168
+ var x, y;
22101
22169
 
22102
22170
  if(titleSide === 'top') {
22103
- y = (1 - (yBottomFrac + lenFrac - ypadFrac)) * gs.h +
22104
- gs.t + 3 + fontSize * 0.75;
22105
- } else {
22106
- y = (1 - (yBottomFrac + ypadFrac)) * gs.h +
22107
- gs.t - 3 - fontSize * 0.25;
22171
+ x = xpad + gs.l + gs.w * optsX;
22172
+ y = ypad + gs.t + gs.h * (1 - vFrac - lenFrac) + 3 + titleFontSize * 0.75;
22173
+ }
22174
+
22175
+ if(titleSide === 'bottom') {
22176
+ x = xpad + gs.l + gs.w * optsX;
22177
+ y = ypad + gs.t + gs.h * (1 - vFrac) - 3 - titleFontSize * 0.25;
22178
+ }
22179
+
22180
+ if(titleSide === 'right') {
22181
+ y = ypad + gs.t + gs.h * optsY + 3 + titleFontSize * 0.75;
22182
+ x = xpad + gs.l + gs.w * vFrac;
22108
22183
  }
22184
+
22109
22185
  drawTitle(ax._id + 'title', {
22110
- attributes: {x: x, y: y, 'text-anchor': 'start'}
22186
+ attributes: {x: x, y: y, 'text-anchor': isVertical ? 'start' : 'middle'}
22111
22187
  });
22112
22188
  }
22113
22189
  }
22114
22190
 
22115
22191
  function drawCbTitle() {
22116
- if(['top', 'bottom'].indexOf(titleSide) === -1) {
22117
- var fontSize = ax.title.font.size;
22118
- var y = ax._offset + ax._length / 2;
22119
- var x = gs.l + (ax.position || 0) * gs.w + ((ax.side === 'right') ?
22120
- 10 + fontSize * ((ax.showticklabels ? 1 : 0.5)) :
22121
- -10 - fontSize * ((ax.showticklabels ? 0.5 : 0)));
22122
-
22123
- // the 'h' + is a hack to get around the fact that
22124
- // convertToTspans rotates any 'y...' class by 90 degrees.
22125
- // TODO: find a better way to control this.
22126
- drawTitle('h' + ax._id + 'title', {
22192
+ if(
22193
+ (isVertical && !topOrBottom) ||
22194
+ (!isVertical && topOrBottom)
22195
+ ) {
22196
+ var pos = ax.position || 0;
22197
+ var mid = ax._offset + ax._length / 2;
22198
+ var x, y;
22199
+
22200
+ if(titleSide === 'right') {
22201
+ y = mid;
22202
+ x = gs.l + gs.w * pos + 10 + titleFontSize * (
22203
+ ax.showticklabels ? 1 : 0.5
22204
+ );
22205
+ } else {
22206
+ x = mid;
22207
+
22208
+ if(titleSide === 'bottom') {
22209
+ y = gs.t + gs.h * pos + 10 + (
22210
+ ticklabelposition.indexOf('inside') === -1 ?
22211
+ ax.tickfont.size :
22212
+ 0
22213
+ ) + (
22214
+ ax.ticks !== 'intside' ?
22215
+ opts.ticklen || 0 :
22216
+ 0
22217
+ );
22218
+ }
22219
+
22220
+ if(titleSide === 'top') {
22221
+ var nlines = title.text.split('<br>').length;
22222
+ y = gs.t + gs.h * pos + 10 - thickPx - LINE_SPACING * titleFontSize * nlines;
22223
+ }
22224
+ }
22225
+
22226
+ drawTitle((isVertical ?
22227
+ // the 'h' + is a hack to get around the fact that
22228
+ // convertToTspans rotates any 'y...' class by 90 degrees.
22229
+ // TODO: find a better way to control this.
22230
+ 'h' :
22231
+ 'v'
22232
+ ) + ax._id + 'title', {
22127
22233
  avoid: {
22128
22234
  selection: d3.select(gd).selectAll('g.' + ax._id + 'tick'),
22129
22235
  side: titleSide,
22130
- offsetLeft: gs.l,
22131
- offsetTop: 0,
22132
- maxShift: fullLayout.width
22236
+ offsetTop: isVertical ? 0 : gs.t,
22237
+ offsetLeft: isVertical ? gs.l : 0,
22238
+ maxShift: isVertical ? fullLayout.width : fullLayout.height
22133
22239
  },
22134
22240
  attributes: {x: x, y: y, 'text-anchor': 'middle'},
22135
- transform: {rotate: '-90', offset: 0}
22241
+ transform: {rotate: isVertical ? -90 : 0, offset: 0}
22136
22242
  });
22137
22243
  }
22138
22244
  }
22139
22245
 
22140
22246
  function drawAxis() {
22141
- if(['top', 'bottom'].indexOf(titleSide) !== -1) {
22247
+ if(
22248
+ (!isVertical && !topOrBottom) ||
22249
+ (isVertical && topOrBottom)
22250
+ ) {
22142
22251
  // squish the axis top to make room for the title
22143
22252
  var titleGroup = g.select('.' + cn.cbtitle);
22144
22253
  var titleText = titleGroup.select('text');
22145
- var titleTrans = [-opts.outlinewidth / 2, opts.outlinewidth / 2];
22254
+ var titleTrans = [-outlinewidth / 2, outlinewidth / 2];
22146
22255
  var mathJaxNode = titleGroup
22147
22256
  .select('.h' + ax._id + 'title-math-group')
22148
22257
  .node();
@@ -22150,39 +22259,63 @@ function drawColorBar(g, opts, gd) {
22150
22259
  if(titleText.node()) {
22151
22260
  lineSize = parseInt(titleText.node().style.fontSize, 10) * LINE_SPACING;
22152
22261
  }
22262
+
22263
+ var bb;
22153
22264
  if(mathJaxNode) {
22154
- titleHeight = Drawing.bBox(mathJaxNode).height;
22265
+ bb = Drawing.bBox(mathJaxNode);
22266
+ titleWidth = bb.width;
22267
+ titleHeight = bb.height;
22155
22268
  if(titleHeight > lineSize) {
22156
22269
  // not entirely sure how mathjax is doing
22157
22270
  // vertical alignment, but this seems to work.
22158
22271
  titleTrans[1] -= (titleHeight - lineSize) / 2;
22159
22272
  }
22160
22273
  } else if(titleText.node() && !titleText.classed(cn.jsPlaceholder)) {
22161
- titleHeight = Drawing.bBox(titleText.node()).height;
22274
+ bb = Drawing.bBox(titleText.node());
22275
+ titleWidth = bb.width;
22276
+ titleHeight = bb.height;
22162
22277
  }
22163
- if(titleHeight) {
22164
- // buffer btwn colorbar and title
22165
- // TODO: configurable
22166
- titleHeight += 5;
22167
22278
 
22168
- if(titleSide === 'top') {
22169
- ax.domain[1] -= titleHeight / gs.h;
22170
- titleTrans[1] *= -1;
22171
- } else {
22172
- ax.domain[0] += titleHeight / gs.h;
22173
- var nlines = svgTextUtils.lineCount(titleText);
22174
- titleTrans[1] += (1 - nlines) * lineSize;
22279
+ if(isVertical) {
22280
+ if(titleHeight) {
22281
+ // buffer btwn colorbar and title
22282
+ // TODO: configurable
22283
+ titleHeight += 5;
22284
+
22285
+ if(titleSide === 'top') {
22286
+ ax.domain[1] -= titleHeight / gs.h;
22287
+ titleTrans[1] *= -1;
22288
+ } else {
22289
+ ax.domain[0] += titleHeight / gs.h;
22290
+ var nlines = svgTextUtils.lineCount(titleText);
22291
+ titleTrans[1] += (1 - nlines) * lineSize;
22292
+ }
22293
+
22294
+ titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22295
+ ax.setScale();
22175
22296
  }
22297
+ } else { // horizontal colorbars
22298
+ if(titleWidth) {
22299
+ if(titleSide === 'right') {
22300
+ ax.domain[0] += (titleWidth + titleFontSize / 2) / gs.w;
22301
+ }
22176
22302
 
22177
- titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22178
- ax.setScale();
22303
+ titleGroup.attr('transform', strTranslate(titleTrans[0], titleTrans[1]));
22304
+ ax.setScale();
22305
+ }
22179
22306
  }
22180
22307
  }
22181
22308
 
22182
22309
  g.selectAll('.' + cn.cbfills + ',.' + cn.cblines)
22183
- .attr('transform', strTranslate(0, Math.round(gs.h * (1 - ax.domain[1]))));
22310
+ .attr('transform', isVertical ?
22311
+ strTranslate(0, Math.round(gs.h * (1 - ax.domain[1]))) :
22312
+ strTranslate(Math.round(gs.w * ax.domain[0]), 0)
22313
+ );
22184
22314
 
22185
- axLayer.attr('transform', strTranslate(0, Math.round(-gs.t)));
22315
+ axLayer.attr('transform', isVertical ?
22316
+ strTranslate(0, Math.round(-gs.t)) :
22317
+ strTranslate(Math.round(-gs.l), 0)
22318
+ );
22186
22319
 
22187
22320
  var fills = g.select('.' + cn.cbfills)
22188
22321
  .selectAll('rect.' + cn.cbfill)
@@ -22208,20 +22341,22 @@ function drawColorBar(g, opts, gd) {
22208
22341
 
22209
22342
  // offset the side adjoining the next rectangle so they
22210
22343
  // overlap, to prevent antialiasing gaps
22211
- z[1] = Lib.constrain(z[1] + (z[1] > z[0]) ? 1 : -1, zBounds[0], zBounds[1]);
22212
-
22344
+ if(isVertical) {
22345
+ z[1] = Lib.constrain(z[1] + (z[1] > z[0]) ? 1 : -1, zBounds[0], zBounds[1]);
22346
+ } /* else {
22347
+ // TODO: horizontal case
22348
+ } */
22213
22349
 
22214
22350
  // Colorbar cannot currently support opacities so we
22215
22351
  // use an opaque fill even when alpha channels present
22216
- var fillEl = d3.select(this).attr({
22217
- x: xLeft,
22218
- width: Math.max(thickPx, 2),
22219
- y: d3.min(z),
22220
- height: Math.max(d3.max(z) - d3.min(z), 2),
22221
- });
22352
+ var fillEl = d3.select(this)
22353
+ .attr(isVertical ? 'x' : 'y', uPx)
22354
+ .attr(isVertical ? 'y' : 'x', d3.min(z))
22355
+ .attr(isVertical ? 'width' : 'height', Math.max(thickPx, 2))
22356
+ .attr(isVertical ? 'height' : 'width', Math.max(d3.max(z) - d3.min(z), 2));
22222
22357
 
22223
22358
  if(opts._fillgradient) {
22224
- Drawing.gradient(fillEl, gd, opts._id, 'vertical', opts._fillgradient, 'fill');
22359
+ Drawing.gradient(fillEl, gd, opts._id, isVertical ? 'vertical' : 'horizontalreversed', opts._fillgradient, 'fill');
22225
22360
  } else {
22226
22361
  // tinycolor can't handle exponents and
22227
22362
  // at this scale, removing it makes no difference.
@@ -22237,17 +22372,23 @@ function drawColorBar(g, opts, gd) {
22237
22372
  .classed(cn.cbline, true);
22238
22373
  lines.exit().remove();
22239
22374
  lines.each(function(d) {
22375
+ var a = uPx;
22376
+ var b = (Math.round(ax.c2p(d)) + (line.width / 2) % 1);
22377
+
22240
22378
  d3.select(this)
22241
- .attr('d', 'M' + xLeft + ',' +
22242
- (Math.round(ax.c2p(d)) + (line.width / 2) % 1) + 'h' + thickPx)
22379
+ .attr('d', 'M' +
22380
+ (isVertical ? a + ',' + b : b + ',' + a) +
22381
+ (isVertical ? 'h' : 'v') +
22382
+ thickPx
22383
+ )
22243
22384
  .call(Drawing.lineGroupStyle, line.width, lineColormap(d), line.dash);
22244
22385
  });
22245
22386
 
22246
22387
  // force full redraw of labels and ticks
22247
22388
  axLayer.selectAll('g.' + ax._id + 'tick,path').remove();
22248
22389
 
22249
- var shift = xLeft + thickPx +
22250
- (opts.outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
22390
+ var shift = uPx + thickPx +
22391
+ (outlinewidth || 0) / 2 - (opts.ticks === 'outside' ? 1 : 0);
22251
22392
 
22252
22393
  var vals = Axes.calcTicks(ax);
22253
22394
  var tickSign = Axes.getTickSigns(ax)[2];
@@ -22272,83 +22413,211 @@ function drawColorBar(g, opts, gd) {
22272
22413
  // TODO: why are we redrawing multiple times now with this?
22273
22414
  // I guess autoMargin doesn't like being post-promise?
22274
22415
  function positionCB() {
22275
- var innerWidth = thickPx + opts.outlinewidth / 2;
22276
- if(ax.ticklabelposition.indexOf('inside') === -1) {
22277
- innerWidth += Drawing.bBox(axLayer.node()).width;
22416
+ var bb;
22417
+ var innerThickness = thickPx + outlinewidth / 2;
22418
+ if(ticklabelposition.indexOf('inside') === -1) {
22419
+ bb = Drawing.bBox(axLayer.node());
22420
+ innerThickness += isVertical ? bb.width : bb.height;
22278
22421
  }
22279
22422
 
22280
22423
  titleEl = titleCont.select('text');
22281
22424
 
22425
+ var titleWidth = 0;
22426
+
22427
+ var topSideVertical = isVertical && titleSide === 'top';
22428
+ var rightSideHorizontal = !isVertical && titleSide === 'right';
22429
+
22430
+ var moveY = 0;
22431
+
22282
22432
  if(titleEl.node() && !titleEl.classed(cn.jsPlaceholder)) {
22433
+ var _titleHeight;
22434
+
22283
22435
  var mathJaxNode = titleCont.select('.h' + ax._id + 'title-math-group').node();
22284
- var titleWidth;
22285
- if(mathJaxNode && ['top', 'bottom'].indexOf(titleSide) !== -1) {
22286
- titleWidth = Drawing.bBox(mathJaxNode).width;
22436
+ if(mathJaxNode && (
22437
+ (isVertical && topOrBottom) ||
22438
+ (!isVertical && !topOrBottom)
22439
+ )) {
22440
+ bb = Drawing.bBox(mathJaxNode);
22441
+ titleWidth = bb.width;
22442
+ _titleHeight = bb.height;
22287
22443
  } else {
22288
22444
  // note: the formula below works for all title sides,
22289
22445
  // (except for top/bottom mathjax, above)
22290
22446
  // but the weird gs.l is because the titleunshift
22291
22447
  // transform gets removed by Drawing.bBox
22292
- titleWidth = Drawing.bBox(titleCont.node()).right - xLeft - gs.l;
22448
+ bb = Drawing.bBox(titleCont.node());
22449
+ titleWidth = bb.right - gs.l - (isVertical ? uPx : vPx);
22450
+ _titleHeight = bb.bottom - gs.t - (isVertical ? vPx : uPx);
22451
+
22452
+ if(
22453
+ !isVertical && titleSide === 'top'
22454
+ ) {
22455
+ innerThickness += bb.height;
22456
+ moveY = bb.height;
22457
+ }
22293
22458
  }
22294
- innerWidth = Math.max(innerWidth, titleWidth);
22459
+
22460
+ if(rightSideHorizontal) {
22461
+ titleEl.attr('transform', strTranslate(titleWidth / 2 + titleFontSize / 2, 0));
22462
+
22463
+ titleWidth *= 2;
22464
+ }
22465
+
22466
+ innerThickness = Math.max(innerThickness,
22467
+ isVertical ? titleWidth : _titleHeight
22468
+ );
22295
22469
  }
22296
22470
 
22297
- var outerwidth = 2 * opts.xpad + innerWidth + opts.borderwidth + opts.outlinewidth / 2;
22298
- var outerheight = yBottomPx - yTopPx;
22471
+ var outerThickness = (isVertical ?
22472
+ xpad :
22473
+ ypad
22474
+ ) * 2 + innerThickness + borderwidth + outlinewidth / 2;
22299
22475
 
22300
- g.select('.' + cn.cbbg).attr({
22301
- x: xLeft - opts.xpad - (opts.borderwidth + opts.outlinewidth) / 2,
22302
- y: yTopPx - yExtraPx,
22303
- width: Math.max(outerwidth, 2),
22304
- height: Math.max(outerheight + 2 * yExtraPx, 2)
22305
- })
22306
- .call(Color.fill, opts.bgcolor)
22307
- .call(Color.stroke, opts.bordercolor)
22308
- .style('stroke-width', opts.borderwidth);
22476
+ var hColorbarMoveTitle = 0;
22477
+ if(!isVertical && title.text && yanchor === 'bottom' && optsY <= 0) {
22478
+ hColorbarMoveTitle = outerThickness / 2;
22309
22479
 
22310
- g.selectAll('.' + cn.cboutline).attr({
22311
- x: xLeft,
22312
- y: yTopPx + opts.ypad + (titleSide === 'top' ? titleHeight : 0),
22313
- width: Math.max(thickPx, 2),
22314
- height: Math.max(outerheight - 2 * opts.ypad - titleHeight, 2)
22315
- })
22480
+ outerThickness += hColorbarMoveTitle;
22481
+ moveY += hColorbarMoveTitle;
22482
+ }
22483
+ fullLayout._hColorbarMoveTitle = hColorbarMoveTitle;
22484
+ fullLayout._hColorbarMoveCBTitle = moveY;
22485
+
22486
+ var extraW = borderwidth + outlinewidth;
22487
+
22488
+ g.select('.' + cn.cbbg)
22489
+ .attr('x', (isVertical ? uPx : vPx) - extraW / 2 - (isVertical ? xpad : 0))
22490
+ .attr('y', (isVertical ? vPx : uPx) - (isVertical ? lenPx : ypad + moveY - hColorbarMoveTitle))
22491
+ .attr(isVertical ? 'width' : 'height', Math.max(outerThickness - hColorbarMoveTitle, 2))
22492
+ .attr(isVertical ? 'height' : 'width', Math.max(lenPx + extraW, 2))
22493
+ .call(Color.fill, bgcolor)
22494
+ .call(Color.stroke, opts.bordercolor)
22495
+ .style('stroke-width', borderwidth);
22496
+
22497
+ var moveX = rightSideHorizontal ? Math.max(titleWidth - 10, 0) : 0;
22498
+
22499
+ g.selectAll('.' + cn.cboutline)
22500
+ .attr('x', (isVertical ? uPx : vPx + xpad) + moveX)
22501
+ .attr('y', (isVertical ? vPx + ypad - lenPx : uPx) + (topSideVertical ? titleHeight : 0))
22502
+ .attr(isVertical ? 'width' : 'height', Math.max(thickPx, 2))
22503
+ .attr(isVertical ? 'height' : 'width', Math.max(lenPx - (isVertical ?
22504
+ 2 * ypad + titleHeight :
22505
+ 2 * xpad + moveX
22506
+ ), 2))
22316
22507
  .call(Color.stroke, opts.outlinecolor)
22317
22508
  .style({
22318
22509
  fill: 'none',
22319
- 'stroke-width': opts.outlinewidth
22510
+ 'stroke-width': outlinewidth
22320
22511
  });
22321
22512
 
22322
- // fix positioning for xanchor!='left'
22323
- var xoffset = ({center: 0.5, right: 1}[opts.xanchor] || 0) * outerwidth;
22324
- g.attr('transform', strTranslate(gs.l - xoffset, gs.t));
22513
+ g.attr('transform', strTranslate(
22514
+ gs.l - (isVertical ? xRatio * outerThickness : 0),
22515
+ gs.t - (isVertical ? 0 : (1 - yRatio) * outerThickness - moveY)
22516
+ ));
22517
+
22518
+ if(!isVertical && (
22519
+ borderwidth || (
22520
+ tinycolor(bgcolor).getAlpha() &&
22521
+ !tinycolor.equals(fullLayout.paper_bgcolor, bgcolor)
22522
+ )
22523
+ )) {
22524
+ // for horizontal colorbars when there is a border line or having different background color
22525
+ // hide/adjust x positioning for the first/last tick labels if they go outside the border
22526
+ var tickLabels = axLayer.selectAll('text');
22527
+ var numTicks = tickLabels[0].length;
22528
+
22529
+ var border = g.select('.' + cn.cbbg).node();
22530
+ var oBb = Drawing.bBox(border);
22531
+ var oTr = Drawing.getTranslate(g);
22532
+
22533
+ var TEXTPAD = 2;
22534
+
22535
+ tickLabels.each(function(d, i) {
22536
+ var first = 0;
22537
+ var last = numTicks - 1;
22538
+ if(i === first || i === last) {
22539
+ var iBb = Drawing.bBox(this);
22540
+ var iTr = Drawing.getTranslate(this);
22541
+ var deltaX;
22542
+
22543
+ if(i === last) {
22544
+ var iRight = iBb.right + iTr.x;
22545
+ var oRight = oBb.right + oTr.x + vPx - borderwidth - TEXTPAD + optsX;
22546
+
22547
+ deltaX = oRight - iRight;
22548
+ if(deltaX > 0) deltaX = 0;
22549
+ } else if(i === first) {
22550
+ var iLeft = iBb.left + iTr.x;
22551
+ var oLeft = oBb.left + oTr.x + vPx + borderwidth + TEXTPAD;
22552
+
22553
+ deltaX = oLeft - iLeft;
22554
+ if(deltaX < 0) deltaX = 0;
22555
+ }
22556
+
22557
+ if(deltaX) {
22558
+ if(numTicks < 3) { // adjust position
22559
+ this.setAttribute('transform',
22560
+ 'translate(' + deltaX + ',0) ' +
22561
+ this.getAttribute('transform')
22562
+ );
22563
+ } else { // hide
22564
+ this.setAttribute('visibility', 'hidden');
22565
+ }
22566
+ }
22567
+ }
22568
+ });
22569
+ }
22325
22570
 
22326
22571
  // auto margin adjustment
22327
22572
  var marginOpts = {};
22328
- var tFrac = FROM_TL[opts.yanchor];
22329
- var bFrac = FROM_BR[opts.yanchor];
22330
- if(opts.lenmode === 'pixels') {
22331
- marginOpts.y = opts.y;
22332
- marginOpts.t = outerheight * tFrac;
22333
- marginOpts.b = outerheight * bFrac;
22334
- } else {
22335
- marginOpts.t = marginOpts.b = 0;
22336
- marginOpts.yt = opts.y + opts.len * tFrac;
22337
- marginOpts.yb = opts.y - opts.len * bFrac;
22338
- }
22573
+ var lFrac = FROM_TL[xanchor];
22574
+ var rFrac = FROM_BR[xanchor];
22575
+ var tFrac = FROM_TL[yanchor];
22576
+ var bFrac = FROM_BR[yanchor];
22339
22577
 
22340
- var lFrac = FROM_TL[opts.xanchor];
22341
- var rFrac = FROM_BR[opts.xanchor];
22342
- if(opts.thicknessmode === 'pixels') {
22343
- marginOpts.x = opts.x;
22344
- marginOpts.l = outerwidth * lFrac;
22345
- marginOpts.r = outerwidth * rFrac;
22346
- } else {
22347
- var extraThickness = outerwidth - thickPx;
22348
- marginOpts.l = extraThickness * lFrac;
22349
- marginOpts.r = extraThickness * rFrac;
22350
- marginOpts.xl = opts.x - opts.thickness * lFrac;
22351
- marginOpts.xr = opts.x + opts.thickness * rFrac;
22578
+ var extraThickness = outerThickness - thickPx;
22579
+ if(isVertical) {
22580
+ if(lenmode === 'pixels') {
22581
+ marginOpts.y = optsY;
22582
+ marginOpts.t = lenPx * tFrac;
22583
+ marginOpts.b = lenPx * bFrac;
22584
+ } else {
22585
+ marginOpts.t = marginOpts.b = 0;
22586
+ marginOpts.yt = optsY + len * tFrac;
22587
+ marginOpts.yb = optsY - len * bFrac;
22588
+ }
22589
+
22590
+ if(thicknessmode === 'pixels') {
22591
+ marginOpts.x = optsX;
22592
+ marginOpts.l = outerThickness * lFrac;
22593
+ marginOpts.r = outerThickness * rFrac;
22594
+ } else {
22595
+ marginOpts.l = extraThickness * lFrac;
22596
+ marginOpts.r = extraThickness * rFrac;
22597
+ marginOpts.xl = optsX - thickness * lFrac;
22598
+ marginOpts.xr = optsX + thickness * rFrac;
22599
+ }
22600
+ } else { // horizontal colorbars
22601
+ if(lenmode === 'pixels') {
22602
+ marginOpts.x = optsX;
22603
+ marginOpts.l = lenPx * lFrac;
22604
+ marginOpts.r = lenPx * rFrac;
22605
+ } else {
22606
+ marginOpts.l = marginOpts.r = 0;
22607
+ marginOpts.xl = optsX + len * lFrac;
22608
+ marginOpts.xr = optsX - len * rFrac;
22609
+ }
22610
+
22611
+ if(thicknessmode === 'pixels') {
22612
+ marginOpts.y = 1 - optsY;
22613
+ marginOpts.t = outerThickness * tFrac;
22614
+ marginOpts.b = outerThickness * bFrac;
22615
+ } else {
22616
+ marginOpts.t = extraThickness * tFrac;
22617
+ marginOpts.b = extraThickness * bFrac;
22618
+ marginOpts.yt = optsY - thickness * tFrac;
22619
+ marginOpts.yb = optsY + thickness * bFrac;
22620
+ }
22352
22621
  }
22353
22622
 
22354
22623
  Plots.autoMargin(gd, opts._id, marginOpts);
@@ -22365,6 +22634,7 @@ function drawColorBar(g, opts, gd) {
22365
22634
  }
22366
22635
 
22367
22636
  function makeEditable(g, opts, gd) {
22637
+ var isVertical = opts.orientation === 'v';
22368
22638
  var fullLayout = gd._fullLayout;
22369
22639
  var gs = fullLayout._size;
22370
22640
  var t0, xf, yf;
@@ -22379,9 +22649,13 @@ function makeEditable(g, opts, gd) {
22379
22649
  moveFn: function(dx, dy) {
22380
22650
  g.attr('transform', t0 + strTranslate(dx, dy));
22381
22651
 
22382
- xf = dragElement.align(opts._xLeftFrac + (dx / gs.w), opts._thickFrac,
22652
+ xf = dragElement.align(
22653
+ (isVertical ? opts._uFrac : opts._vFrac) + (dx / gs.w),
22654
+ isVertical ? opts._thickFrac : opts._lenFrac,
22383
22655
  0, 1, opts.xanchor);
22384
- yf = dragElement.align(opts._yBottomFrac - (dy / gs.h), opts._lenFrac,
22656
+ yf = dragElement.align(
22657
+ (isVertical ? opts._vFrac : (1 - opts._uFrac)) - (dy / gs.h),
22658
+ isVertical ? opts._lenFrac : opts._thickFrac,
22385
22659
  0, 1, opts.yanchor);
22386
22660
 
22387
22661
  var csr = dragElement.getCursor(xf, yf, opts.xanchor, opts.yanchor);
@@ -22458,6 +22732,8 @@ function calcLevels(gd, opts, zrange) {
22458
22732
  function mockColorBarAxis(gd, opts, zrange) {
22459
22733
  var fullLayout = gd._fullLayout;
22460
22734
 
22735
+ var isVertical = opts.orientation === 'v';
22736
+
22461
22737
  var cbAxisIn = {
22462
22738
  type: 'linear',
22463
22739
  range: zrange,
@@ -22488,17 +22764,19 @@ function mockColorBarAxis(gd, opts, zrange) {
22488
22764
  title: opts.title,
22489
22765
  showline: true,
22490
22766
  anchor: 'free',
22491
- side: 'right',
22767
+ side: isVertical ? 'right' : 'bottom',
22492
22768
  position: 1
22493
22769
  };
22494
22770
 
22771
+ var letter = isVertical ? 'y' : 'x';
22772
+
22495
22773
  var cbAxisOut = {
22496
22774
  type: 'linear',
22497
- _id: 'y' + opts._id
22775
+ _id: letter + opts._id
22498
22776
  };
22499
22777
 
22500
22778
  var axisOptions = {
22501
- letter: 'y',
22779
+ letter: letter,
22502
22780
  font: fullLayout.font,
22503
22781
  noHover: true,
22504
22782
  noTickson: true,
@@ -24960,7 +25238,7 @@ var TEXTOFFSETSIGN = {
24960
25238
  start: 1, end: -1, middle: 0, bottom: 1, top: -1
24961
25239
  };
24962
25240
 
24963
- function textPointPosition(s, textPosition, fontSize, markerRadius) {
25241
+ function textPointPosition(s, textPosition, fontSize, markerRadius, dontTouchParent) {
24964
25242
  var group = d3.select(s.node().parentNode);
24965
25243
 
24966
25244
  var v = textPosition.indexOf('top') !== -1 ?
@@ -24982,7 +25260,9 @@ function textPointPosition(s, textPosition, fontSize, markerRadius) {
24982
25260
 
24983
25261
  // fix the overall text group position
24984
25262
  s.attr('text-anchor', h);
24985
- group.attr('transform', strTranslate(dx, dy));
25263
+ if(!dontTouchParent) {
25264
+ group.attr('transform', strTranslate(dx, dy));
25265
+ }
24986
25266
  }
24987
25267
 
24988
25268
  function extracTextFontSize(d, trace) {
@@ -25052,7 +25332,8 @@ drawing.selectedTextStyle = function(s, trace) {
25052
25332
  var fontSize = extracTextFontSize(d, trace);
25053
25333
 
25054
25334
  Color.fill(tx, tc);
25055
- textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc);
25335
+ var dontTouchParent = Registry.traceIs(trace, 'bar-like');
25336
+ textPointPosition(tx, tp, fontSize, d.mrc2 || d.mrc, dontTouchParent);
25056
25337
  });
25057
25338
  };
25058
25339
 
@@ -27083,11 +27364,13 @@ var cartesianScatterPoints = {
27083
27364
  // The actual rendering is done by private function _hover.
27084
27365
  exports.hover = function hover(gd, evt, subplot, noHoverEvent) {
27085
27366
  gd = Lib.getGraphDiv(gd);
27086
-
27367
+ // The 'target' property changes when bubbling out of Shadow DOM.
27368
+ // Throttling can delay reading the target, so we save the current value.
27369
+ var eventTarget = evt.target;
27087
27370
  Lib.throttle(
27088
27371
  gd._fullLayout._uid + constants.HOVERID,
27089
27372
  constants.HOVERMINTIME,
27090
- function() { _hover(gd, evt, subplot, noHoverEvent); }
27373
+ function() { _hover(gd, evt, subplot, noHoverEvent, eventTarget); }
27091
27374
  );
27092
27375
  };
27093
27376
 
@@ -27252,7 +27535,7 @@ exports.loneHover = function loneHover(hoverItems, opts) {
27252
27535
  };
27253
27536
 
27254
27537
  // The actual implementation is here:
27255
- function _hover(gd, evt, subplot, noHoverEvent) {
27538
+ function _hover(gd, evt, subplot, noHoverEvent, eventTarget) {
27256
27539
  if(!subplot) subplot = 'xy';
27257
27540
 
27258
27541
  // if the user passed in an array of subplots,
@@ -27371,7 +27654,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
27371
27654
  // [x|y]px: the pixels (from top left) of the mouse location
27372
27655
  // on the currently selected plot area
27373
27656
  // add pointerX|Y property for drawing the spikes in spikesnap 'cursor' situation
27374
- var hasUserCalledHover = !evt.target;
27657
+ var hasUserCalledHover = !eventTarget;
27375
27658
  var xpx, ypx;
27376
27659
 
27377
27660
  if(hasUserCalledHover) {
@@ -27388,13 +27671,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
27388
27671
  return;
27389
27672
  }
27390
27673
 
27391
- // Discover event target, traversing open shadow roots.
27392
- var target = evt.composedPath && evt.composedPath()[0];
27393
- if(!target) {
27394
- // Fallback for browsers not supporting composedPath
27395
- target = evt.target;
27396
- }
27397
- var dbb = target.getBoundingClientRect();
27674
+ var dbb = eventTarget.getBoundingClientRect();
27398
27675
 
27399
27676
  xpx = evt.clientX - dbb.left;
27400
27677
  ypx = evt.clientY - dbb.top;
@@ -27842,15 +28119,15 @@ function _hover(gd, evt, subplot, noHoverEvent) {
27842
28119
  if(!helpers.isUnifiedHover(hovermode)) {
27843
28120
  hoverAvoidOverlaps(hoverLabels, rotateLabels ? 'xa' : 'ya', fullLayout);
27844
28121
  alignHoverText(hoverLabels, rotateLabels, fullLayout._invScaleX, fullLayout._invScaleY);
27845
- } // TODO: tagName hack is needed to appease geo.js's hack of using evt.target=true
28122
+ } // TODO: tagName hack is needed to appease geo.js's hack of using eventTarget=true
27846
28123
  // we should improve the "fx" API so other plots can use it without these hack.
27847
- if(evt.target && evt.target.tagName) {
28124
+ if(eventTarget && eventTarget.tagName) {
27848
28125
  var hasClickToShow = Registry.getComponentMethod('annotations', 'hasClickToShow')(gd, newhoverdata);
27849
- overrideCursor(d3.select(evt.target), hasClickToShow ? 'pointer' : '');
28126
+ overrideCursor(d3.select(eventTarget), hasClickToShow ? 'pointer' : '');
27850
28127
  }
27851
28128
 
27852
28129
  // don't emit events if called manually
27853
- if(!evt.target || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
28130
+ if(!eventTarget || noHoverEvent || !hoverChanged(gd, evt, oldhoverdata)) return;
27854
28131
 
27855
28132
  if(oldhoverdata) {
27856
28133
  gd.emit('plotly_unhover', {
@@ -28112,7 +28389,9 @@ function createHoverText(hoverData, opts) {
28112
28389
  orientation: 'v'
28113
28390
  }
28114
28391
  };
28115
- var mockLayoutOut = {};
28392
+ var mockLayoutOut = {
28393
+ font: font
28394
+ };
28116
28395
  legendSupplyDefaults(mockLayoutIn, mockLayoutOut, gd._fullData);
28117
28396
  var mockLegend = mockLayoutOut.legend;
28118
28397
 
@@ -28153,7 +28432,8 @@ function createHoverText(hoverData, opts) {
28153
28432
 
28154
28433
  // Draw unified hover label
28155
28434
  mockLegend._inHover = true;
28156
- mockLegend._groupTitleFont = font;
28435
+ mockLegend._groupTitleFont = hoverlabel.grouptitlefont;
28436
+
28157
28437
  legendDraw(gd, mockLegend);
28158
28438
 
28159
28439
  // Position the hover
@@ -29155,9 +29435,11 @@ var isUnifiedHover = _dereq_('./helpers').isUnifiedHover;
29155
29435
  module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts) {
29156
29436
  opts = opts || {};
29157
29437
 
29438
+ var hasLegend = contOut.legend;
29439
+
29158
29440
  function inheritFontAttr(attr) {
29159
29441
  if(!opts.font[attr]) {
29160
- opts.font[attr] = contOut.legend ? contOut.legend.font[attr] : contOut.font[attr];
29442
+ opts.font[attr] = hasLegend ? contOut.legend.font[attr] : contOut.font[attr];
29161
29443
  }
29162
29444
  }
29163
29445
 
@@ -29168,7 +29450,7 @@ module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts
29168
29450
  inheritFontAttr('family');
29169
29451
  inheritFontAttr('color');
29170
29452
 
29171
- if(contOut.legend) {
29453
+ if(hasLegend) {
29172
29454
  if(!opts.bgcolor) opts.bgcolor = Color.combine(contOut.legend.bgcolor, contOut.paper_bgcolor);
29173
29455
  if(!opts.bordercolor) opts.bordercolor = contOut.legend.bordercolor;
29174
29456
  } else {
@@ -29277,11 +29559,13 @@ function castHoverinfo(trace, fullLayout, ptNumber) {
29277
29559
 
29278
29560
  var constants = _dereq_('./constants');
29279
29561
 
29280
- var fontAttrs = _dereq_('../../plots/font_attributes')({
29562
+ var fontAttrs = _dereq_('../../plots/font_attributes');
29563
+
29564
+ var font = fontAttrs({
29281
29565
  editType: 'none',
29282
29566
  });
29283
- fontAttrs.family.dflt = constants.HOVERFONT;
29284
- fontAttrs.size.dflt = constants.HOVERFONTSIZE;
29567
+ font.family.dflt = constants.HOVERFONT;
29568
+ font.size.dflt = constants.HOVERFONTSIZE;
29285
29569
 
29286
29570
  module.exports = {
29287
29571
  clickmode: {
@@ -29337,7 +29621,10 @@ module.exports = {
29337
29621
  valType: 'color',
29338
29622
  editType: 'none',
29339
29623
  },
29340
- font: fontAttrs,
29624
+ font: font,
29625
+ grouptitlefont: fontAttrs({
29626
+ editType: 'none',
29627
+ }),
29341
29628
  align: {
29342
29629
  valType: 'enumerated',
29343
29630
  values: ['left', 'right', 'auto'],
@@ -29350,6 +29637,7 @@ module.exports = {
29350
29637
  dflt: 15,
29351
29638
  editType: 'none',
29352
29639
  },
29640
+
29353
29641
  editType: 'none'
29354
29642
  },
29355
29643
  selectdirection: {
@@ -29397,6 +29685,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
29397
29685
  }
29398
29686
 
29399
29687
  handleHoverLabelDefaults(layoutIn, layoutOut, coerce);
29688
+
29689
+ Lib.coerceFont(coerce, 'hoverlabel.grouptitlefont', layoutOut.hoverlabel.font);
29400
29690
  };
29401
29691
 
29402
29692
  },{"../../lib":232,"./hoverlabel_defaults":140,"./hovermode_defaults":141,"./layout_attributes":143}],145:[function(_dereq_,module,exports){
@@ -30280,6 +30570,9 @@ module.exports = {
30280
30570
  font: fontAttrs({
30281
30571
  editType: 'legend',
30282
30572
  }),
30573
+ grouptitlefont: fontAttrs({
30574
+ editType: 'legend',
30575
+ }),
30283
30576
  orientation: {
30284
30577
  valType: 'enumerated',
30285
30578
  values: ['v', 'h'],
@@ -30403,6 +30696,7 @@ var Registry = _dereq_('../../registry');
30403
30696
  var Lib = _dereq_('../../lib');
30404
30697
  var Template = _dereq_('../../plot_api/plot_template');
30405
30698
 
30699
+ var plotsAttrs = _dereq_('../../plots/attributes');
30406
30700
  var attributes = _dereq_('./attributes');
30407
30701
  var basePlotLayoutAttributes = _dereq_('../../plots/layout_attributes');
30408
30702
  var helpers = _dereq_('./helpers');
@@ -30410,13 +30704,30 @@ var helpers = _dereq_('./helpers');
30410
30704
 
30411
30705
  module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
30412
30706
  var containerIn = layoutIn.legend || {};
30707
+ var containerOut = Template.newContainer(layoutOut, 'legend');
30708
+
30709
+ function coerce(attr, dflt) {
30710
+ return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
30711
+ }
30712
+
30713
+ var trace;
30714
+ var traceCoerce = function(attr, dflt) {
30715
+ var traceIn = trace._input;
30716
+ var traceOut = trace;
30717
+ return Lib.coerce(traceIn, traceOut, plotsAttrs, attr, dflt);
30718
+ };
30719
+
30720
+ var globalFont = layoutOut.font || {};
30721
+ var grouptitlefont = Lib.coerceFont(coerce, 'grouptitlefont', Lib.extendFlat({}, globalFont, {
30722
+ size: Math.round(globalFont.size * 1.1)
30723
+ }));
30413
30724
 
30414
30725
  var legendTraceCount = 0;
30415
30726
  var legendReallyHasATrace = false;
30416
30727
  var defaultOrder = 'normal';
30417
30728
 
30418
30729
  for(var i = 0; i < fullData.length; i++) {
30419
- var trace = fullData[i];
30730
+ trace = fullData[i];
30420
30731
 
30421
30732
  if(!trace.visible) continue;
30422
30733
 
@@ -30443,6 +30754,8 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
30443
30754
  legendTraceCount++;
30444
30755
  }
30445
30756
  }
30757
+
30758
+ Lib.coerceFont(traceCoerce, 'legendgrouptitle.font', grouptitlefont);
30446
30759
  }
30447
30760
 
30448
30761
  if((Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
@@ -30461,13 +30774,10 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
30461
30774
  basePlotLayoutAttributes, 'showlegend',
30462
30775
  legendReallyHasATrace && legendTraceCount > 1);
30463
30776
 
30464
- if(showLegend === false && !containerIn.uirevision) return;
30777
+ // delete legend
30778
+ if(showLegend === false) layoutOut.legend = undefined;
30465
30779
 
30466
- var containerOut = Template.newContainer(layoutOut, 'legend');
30467
-
30468
- function coerce(attr, dflt) {
30469
- return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
30470
- }
30780
+ if(showLegend === false && !containerIn.uirevision) return;
30471
30781
 
30472
30782
  coerce('uirevision', layoutOut.uirevision);
30473
30783
 
@@ -30529,7 +30839,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
30529
30839
  }
30530
30840
  };
30531
30841
 
30532
- },{"../../lib":232,"../../plot_api/plot_template":268,"../../plots/layout_attributes":314,"../../registry":318,"./attributes":152,"./helpers":158}],155:[function(_dereq_,module,exports){
30842
+ },{"../../lib":232,"../../plot_api/plot_template":268,"../../plots/attributes":275,"../../plots/layout_attributes":314,"../../registry":318,"./attributes":152,"./helpers":158}],155:[function(_dereq_,module,exports){
30533
30843
  'use strict';
30534
30844
 
30535
30845
  var d3 = _dereq_('@plotly/d3');
@@ -38981,8 +39291,10 @@ function draw(gd, titleClass, options) {
38981
39291
 
38982
39292
  var elShouldExist = txt || editable;
38983
39293
 
39294
+ var hColorbarMoveTitle;
38984
39295
  if(!group) {
38985
39296
  group = Lib.ensureSingle(fullLayout._infolayer, 'g', 'g-' + titleClass);
39297
+ hColorbarMoveTitle = fullLayout._hColorbarMoveTitle;
38986
39298
  }
38987
39299
 
38988
39300
  var el = group.selectAll('text')
@@ -39006,13 +39318,17 @@ function draw(gd, titleClass, options) {
39006
39318
  function drawTitle(titleEl) {
39007
39319
  var transformVal;
39008
39320
 
39321
+ if(!transform && hColorbarMoveTitle) {
39322
+ transform = {};
39323
+ }
39324
+
39009
39325
  if(transform) {
39010
39326
  transformVal = '';
39011
39327
  if(transform.rotate) {
39012
39328
  transformVal += 'rotate(' + [transform.rotate, attributes.x, attributes.y] + ')';
39013
39329
  }
39014
- if(transform.offset) {
39015
- transformVal += strTranslate(0, transform.offset);
39330
+ if(transform.offset || hColorbarMoveTitle) {
39331
+ transformVal += strTranslate(0, (transform.offset || 0) - (hColorbarMoveTitle || 0));
39016
39332
  }
39017
39333
  } else {
39018
39334
  transformVal = null;
@@ -50470,7 +50786,7 @@ function cleanDeprecatedAttributeKeys(aobj) {
50470
50786
  if((key === 'title' || oldAxisTitleRegex.test(key) || colorbarRegex.test(key)) &&
50471
50787
  (typeof value === 'string' || typeof value === 'number')) {
50472
50788
  replace(key, key.replace('title', 'title.text'));
50473
- } else if(key.indexOf('titlefont') > -1) {
50789
+ } else if(key.indexOf('titlefont') > -1 && key.indexOf('grouptitlefont') === -1) {
50474
50790
  replace(key, key.replace('titlefont', 'title.font'));
50475
50791
  } else if(key.indexOf('titleposition') > -1) {
50476
50792
  replace(key, key.replace('titleposition', 'title.position'));
@@ -51147,7 +51463,8 @@ function findUIPattern(key, patternSpecs) {
51147
51463
  var spec = patternSpecs[i];
51148
51464
  var match = key.match(spec.pattern);
51149
51465
  if(match) {
51150
- return {head: match[1], attr: spec.attr};
51466
+ var head = match[1] || '';
51467
+ return {head: head, tail: key.substr(head.length + 1), attr: spec.attr};
51151
51468
  }
51152
51469
  }
51153
51470
  }
@@ -51199,26 +51516,54 @@ function valsMatch(v1, v2) {
51199
51516
 
51200
51517
  function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
51201
51518
  var layoutPreGUI = oldFullLayout._preGUI;
51202
- var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal;
51519
+ var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal, head, tail;
51203
51520
  var bothInheritAutorange = [];
51521
+ var newAutorangeIn = {};
51204
51522
  var newRangeAccepted = {};
51205
51523
  for(key in layoutPreGUI) {
51206
51524
  match = findUIPattern(key, layoutUIControlPatterns);
51207
51525
  if(match) {
51208
- revAttr = match.attr || (match.head + '.uirevision');
51526
+ head = match.head;
51527
+ tail = match.tail;
51528
+ revAttr = match.attr || (head + '.uirevision');
51209
51529
  oldRev = nestedProperty(oldFullLayout, revAttr).get();
51210
51530
  newRev = oldRev && getNewRev(revAttr, layout);
51531
+
51211
51532
  if(newRev && (newRev === oldRev)) {
51212
51533
  preGUIVal = layoutPreGUI[key];
51213
51534
  if(preGUIVal === null) preGUIVal = undefined;
51214
51535
  newNP = nestedProperty(layout, key);
51215
51536
  newVal = newNP.get();
51537
+
51216
51538
  if(valsMatch(newVal, preGUIVal)) {
51217
- if(newVal === undefined && key.substr(key.length - 9) === 'autorange') {
51218
- bothInheritAutorange.push(key.substr(0, key.length - 10));
51539
+ if(newVal === undefined && tail === 'autorange') {
51540
+ bothInheritAutorange.push(head);
51219
51541
  }
51220
51542
  newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
51221
51543
  continue;
51544
+ } else if(tail === 'autorange' || tail.substr(0, 6) === 'range[') {
51545
+ // Special case for (auto)range since we push it back into the layout
51546
+ // so all null should be treated equivalently to autorange: true with any range
51547
+ var pre0 = layoutPreGUI[head + '.range[0]'];
51548
+ var pre1 = layoutPreGUI[head + '.range[1]'];
51549
+ var preAuto = layoutPreGUI[head + '.autorange'];
51550
+ if(preAuto || (preAuto === null && pre0 === null && pre1 === null)) {
51551
+ // Only read the input layout once and stash the result,
51552
+ // so we get it before we start modifying it
51553
+ if(!(head in newAutorangeIn)) {
51554
+ var newContainer = nestedProperty(layout, head).get();
51555
+ newAutorangeIn[head] = newContainer && (
51556
+ newContainer.autorange ||
51557
+ (newContainer.autorange !== false && (
51558
+ !newContainer.range || newContainer.range.length !== 2)
51559
+ )
51560
+ );
51561
+ }
51562
+ if(newAutorangeIn[head]) {
51563
+ newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
51564
+ continue;
51565
+ }
51566
+ }
51222
51567
  }
51223
51568
  }
51224
51569
  } else {
@@ -51229,12 +51574,12 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
51229
51574
  // so remove it from _preGUI for next time.
51230
51575
  delete layoutPreGUI[key];
51231
51576
 
51232
- if(key.substr(key.length - 8, 6) === 'range[') {
51233
- newRangeAccepted[key.substr(0, key.length - 9)] = 1;
51577
+ if(match && match.tail.substr(0, 6) === 'range[') {
51578
+ newRangeAccepted[match.head] = 1;
51234
51579
  }
51235
51580
  }
51236
51581
 
51237
- // Special logic for `autorange`, since it interacts with `range`:
51582
+ // More special logic for `autorange`, since it interacts with `range`:
51238
51583
  // If the new figure's matching `range` was kept, and `autorange`
51239
51584
  // wasn't supplied explicitly in either the original or the new figure,
51240
51585
  // we shouldn't alter that - but we may just have done that, so fix it.
@@ -68309,6 +68654,9 @@ module.exports = function(opts) {
68309
68654
  // TODO - that's uber hacky... better solution?
68310
68655
  };
68311
68656
 
68657
+ if(opts.autoSize) attrs.size.dflt = 'auto';
68658
+ if(opts.autoColor) attrs.color.dflt = 'auto';
68659
+
68312
68660
  if(opts.arrayOk) {
68313
68661
  attrs.family.arrayOk = true;
68314
68662
  attrs.size.arrayOk = true;
@@ -68668,6 +69016,7 @@ module.exports = {
68668
69016
  valType: 'boolean',
68669
69017
  editType: 'legend',
68670
69018
  },
69019
+
68671
69020
  colorway: {
68672
69021
  valType: 'colorlist',
68673
69022
  dflt: colorAttrs.defaults,
@@ -70080,13 +70429,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
70080
70429
  );
70081
70430
 
70082
70431
  coerce('legendgroup');
70083
- var titleText = coerce('legendgrouptitle.text');
70084
- if(titleText) {
70085
- Lib.coerceFont(coerce, 'legendgrouptitle.font', Lib.extendFlat({}, layout.font, {
70086
- size: Math.round(layout.font.size * 1.1) // default to larger font size
70087
- }));
70088
- }
70089
-
70432
+ coerce('legendgrouptitle.text');
70090
70433
  coerce('legendrank');
70091
70434
 
70092
70435
  traceOut._dfltShowLegend = true;
@@ -70234,16 +70577,14 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {
70234
70577
 
70235
70578
  coerce('autotypenumbers');
70236
70579
 
70237
- var globalFont = Lib.coerceFont(coerce, 'font');
70238
-
70239
- coerce('title.text', layoutOut._dfltTitle.plot);
70580
+ var font = Lib.coerceFont(coerce, 'font');
70581
+ var fontSize = font.size;
70240
70582
 
70241
- Lib.coerceFont(coerce, 'title.font', {
70242
- family: globalFont.family,
70243
- size: Math.round(globalFont.size * 1.4),
70244
- color: globalFont.color
70245
- });
70583
+ Lib.coerceFont(coerce, 'title.font', Lib.extendFlat({}, font, {
70584
+ size: Math.round(fontSize * 1.4)
70585
+ }));
70246
70586
 
70587
+ coerce('title.text', layoutOut._dfltTitle.plot);
70247
70588
  coerce('title.xref');
70248
70589
  coerce('title.yref');
70249
70590
  coerce('title.x');
@@ -75580,7 +75921,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
75580
75921
  }
75581
75922
 
75582
75923
  transform.fontSize = font.size;
75583
- recordMinTextSize(trace.type, transform, fullLayout);
75924
+ recordMinTextSize(trace.type === 'histogram' ? 'bar' : trace.type, transform, fullLayout);
75584
75925
  calcBar.transform = transform;
75585
75926
 
75586
75927
  transition(textSelection, fullLayout, opts, makeOnCompleteCallback)
@@ -76648,7 +76989,6 @@ function calc(gd, trace) {
76648
76989
  v = vals[i];
76649
76990
  if(!isNumeric(v)) continue;
76650
76991
  v = +v;
76651
- if(v < 0) continue;
76652
76992
  } else v = 1;
76653
76993
 
76654
76994
  label = labels[i];
@@ -76685,6 +77025,9 @@ function calc(gd, trace) {
76685
77025
  }
76686
77026
  }
76687
77027
 
77028
+ // Drop aggregate sums of value 0 or less
77029
+ cd = cd.filter(function(elem) { return elem.v >= 0; });
77030
+
76688
77031
  var shouldSort = (trace.type === 'funnelarea') ? isAggregated : trace.sort;
76689
77032
  if(shouldSort) cd.sort(function(a, b) { return b.v - a.v; });
76690
77033
 
@@ -82281,7 +82624,7 @@ function getSortFunc(opts, d2c) {
82281
82624
  'use strict';
82282
82625
 
82283
82626
  // package version injected by `npm run preprocess`
82284
- exports.version = '2.6.2';
82627
+ exports.version = '2.8.0';
82285
82628
 
82286
82629
  },{}]},{},[8])(8)
82287
82630
  });