plotly.js 2.7.0 → 2.8.3

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 (54) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +3 -3
  3. package/dist/README.md +26 -26
  4. package/dist/plot-schema.json +898 -407
  5. package/dist/plotly-basic.js +497 -186
  6. package/dist/plotly-basic.min.js +4 -4
  7. package/dist/plotly-cartesian.js +907 -329
  8. package/dist/plotly-cartesian.min.js +3 -3
  9. package/dist/plotly-finance.js +500 -188
  10. package/dist/plotly-finance.min.js +4 -4
  11. package/dist/plotly-geo-assets.js +2 -2
  12. package/dist/plotly-geo.js +486 -184
  13. package/dist/plotly-geo.min.js +4 -4
  14. package/dist/plotly-gl2d.js +505 -187
  15. package/dist/plotly-gl2d.min.js +2 -2
  16. package/dist/plotly-gl3d.js +486 -184
  17. package/dist/plotly-gl3d.min.js +2 -2
  18. package/dist/plotly-mapbox.js +486 -184
  19. package/dist/plotly-mapbox.min.js +2 -2
  20. package/dist/plotly-strict.js +1125 -547
  21. package/dist/plotly-strict.min.js +3 -3
  22. package/dist/plotly-with-meta.js +1214 -609
  23. package/dist/plotly.js +1179 -601
  24. package/dist/plotly.min.js +10 -10
  25. package/package.json +4 -4
  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 +374 -128
  29. package/src/components/fx/hover.js +5 -2
  30. package/src/components/fx/hoverlabel_defaults.js +4 -2
  31. package/src/components/fx/layout_attributes.js +14 -4
  32. package/src/components/fx/layout_defaults.js +2 -0
  33. package/src/components/legend/attributes.js +7 -0
  34. package/src/components/legend/defaults.js +24 -7
  35. package/src/components/titles/index.js +8 -2
  36. package/src/plot_api/plot_api.js +1 -1
  37. package/src/plots/font_attributes.js +3 -0
  38. package/src/plots/layout_attributes.js +1 -0
  39. package/src/plots/plots.js +7 -15
  40. package/src/traces/bar/plot.js +8 -1
  41. package/src/traces/contour/attributes.js +12 -0
  42. package/src/traces/contour/defaults.js +9 -1
  43. package/src/traces/heatmap/attributes.js +16 -0
  44. package/src/traces/heatmap/defaults.js +2 -0
  45. package/src/traces/heatmap/label_defaults.js +13 -0
  46. package/src/traces/heatmap/plot.js +205 -4
  47. package/src/traces/histogram/calc.js +3 -2
  48. package/src/traces/histogram2d/attributes.js +8 -0
  49. package/src/traces/histogram2d/defaults.js +4 -0
  50. package/src/traces/histogram2dcontour/attributes.js +3 -1
  51. package/src/traces/histogram2dcontour/defaults.js +8 -1
  52. package/src/traces/pie/calc.js +3 -1
  53. package/src/version.js +1 -1
  54. package/tasks/test_mock.js +1 -0
@@ -1103,7 +1103,9 @@ function createHoverText(hoverData, opts) {
1103
1103
  orientation: 'v'
1104
1104
  }
1105
1105
  };
1106
- var mockLayoutOut = {};
1106
+ var mockLayoutOut = {
1107
+ font: font
1108
+ };
1107
1109
  legendSupplyDefaults(mockLayoutIn, mockLayoutOut, gd._fullData);
1108
1110
  var mockLegend = mockLayoutOut.legend;
1109
1111
 
@@ -1144,7 +1146,8 @@ function createHoverText(hoverData, opts) {
1144
1146
 
1145
1147
  // Draw unified hover label
1146
1148
  mockLegend._inHover = true;
1147
- mockLegend._groupTitleFont = font;
1149
+ mockLegend._groupTitleFont = hoverlabel.grouptitlefont;
1150
+
1148
1151
  legendDraw(gd, mockLegend);
1149
1152
 
1150
1153
  // Position the hover
@@ -7,9 +7,11 @@ var isUnifiedHover = require('./helpers').isUnifiedHover;
7
7
  module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts) {
8
8
  opts = opts || {};
9
9
 
10
+ var hasLegend = contOut.legend;
11
+
10
12
  function inheritFontAttr(attr) {
11
13
  if(!opts.font[attr]) {
12
- opts.font[attr] = contOut.legend ? contOut.legend.font[attr] : contOut.font[attr];
14
+ opts.font[attr] = hasLegend ? contOut.legend.font[attr] : contOut.font[attr];
13
15
  }
14
16
  }
15
17
 
@@ -20,7 +22,7 @@ module.exports = function handleHoverLabelDefaults(contIn, contOut, coerce, opts
20
22
  inheritFontAttr('family');
21
23
  inheritFontAttr('color');
22
24
 
23
- if(contOut.legend) {
25
+ if(hasLegend) {
24
26
  if(!opts.bgcolor) opts.bgcolor = Color.combine(contOut.legend.bgcolor, contOut.paper_bgcolor);
25
27
  if(!opts.bordercolor) opts.bordercolor = contOut.legend.bordercolor;
26
28
  } else {
@@ -2,12 +2,14 @@
2
2
 
3
3
  var constants = require('./constants');
4
4
 
5
- var fontAttrs = require('../../plots/font_attributes')({
5
+ var fontAttrs = require('../../plots/font_attributes');
6
+
7
+ var font = fontAttrs({
6
8
  editType: 'none',
7
9
  description: 'Sets the default hover label font used by all traces on the graph.'
8
10
  });
9
- fontAttrs.family.dflt = constants.HOVERFONT;
10
- fontAttrs.size.dflt = constants.HOVERFONTSIZE;
11
+ font.family.dflt = constants.HOVERFONT;
12
+ font.size.dflt = constants.HOVERFONTSIZE;
11
13
 
12
14
  module.exports = {
13
15
  clickmode: {
@@ -118,7 +120,14 @@ module.exports = {
118
120
  'Sets the border color of all hover labels on graph.'
119
121
  ].join(' ')
120
122
  },
121
- font: fontAttrs,
123
+ font: font,
124
+ grouptitlefont: fontAttrs({
125
+ editType: 'none',
126
+ description: [
127
+ 'Sets the font for group titles in hover (unified modes).',
128
+ 'Defaults to `hoverlabel.font`.'
129
+ ].join(' ')
130
+ }),
122
131
  align: {
123
132
  valType: 'enumerated',
124
133
  values: ['left', 'right', 'auto'],
@@ -143,6 +152,7 @@ module.exports = {
143
152
  '`namelength - 3` characters and add an ellipsis.'
144
153
  ].join(' ')
145
154
  },
155
+
146
156
  editType: 'none'
147
157
  },
148
158
  selectdirection: {
@@ -34,4 +34,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
34
34
  }
35
35
 
36
36
  handleHoverLabelDefaults(layoutIn, layoutOut, coerce);
37
+
38
+ Lib.coerceFont(coerce, 'hoverlabel.grouptitlefont', layoutOut.hoverlabel.font);
37
39
  };
@@ -30,6 +30,13 @@ module.exports = {
30
30
  editType: 'legend',
31
31
  description: 'Sets the font used to text the legend items.'
32
32
  }),
33
+ grouptitlefont: fontAttrs({
34
+ editType: 'legend',
35
+ description: [
36
+ 'Sets the font for group titles in legend.',
37
+ 'Defaults to `legend.font` with its size increased about 10%.'
38
+ ].join(' ')
39
+ }),
33
40
  orientation: {
34
41
  valType: 'enumerated',
35
42
  values: ['v', 'h'],
@@ -4,6 +4,7 @@ var Registry = require('../../registry');
4
4
  var Lib = require('../../lib');
5
5
  var Template = require('../../plot_api/plot_template');
6
6
 
7
+ var plotsAttrs = require('../../plots/attributes');
7
8
  var attributes = require('./attributes');
8
9
  var basePlotLayoutAttributes = require('../../plots/layout_attributes');
9
10
  var helpers = require('./helpers');
@@ -11,13 +12,30 @@ var helpers = require('./helpers');
11
12
 
12
13
  module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
13
14
  var containerIn = layoutIn.legend || {};
15
+ var containerOut = Template.newContainer(layoutOut, 'legend');
16
+
17
+ function coerce(attr, dflt) {
18
+ return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
19
+ }
20
+
21
+ var trace;
22
+ var traceCoerce = function(attr, dflt) {
23
+ var traceIn = trace._input;
24
+ var traceOut = trace;
25
+ return Lib.coerce(traceIn, traceOut, plotsAttrs, attr, dflt);
26
+ };
27
+
28
+ var globalFont = layoutOut.font || {};
29
+ var grouptitlefont = Lib.coerceFont(coerce, 'grouptitlefont', Lib.extendFlat({}, globalFont, {
30
+ size: Math.round(globalFont.size * 1.1)
31
+ }));
14
32
 
15
33
  var legendTraceCount = 0;
16
34
  var legendReallyHasATrace = false;
17
35
  var defaultOrder = 'normal';
18
36
 
19
37
  for(var i = 0; i < fullData.length; i++) {
20
- var trace = fullData[i];
38
+ trace = fullData[i];
21
39
 
22
40
  if(!trace.visible) continue;
23
41
 
@@ -44,6 +62,8 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
44
62
  legendTraceCount++;
45
63
  }
46
64
  }
65
+
66
+ Lib.coerceFont(traceCoerce, 'legendgrouptitle.font', grouptitlefont);
47
67
  }
48
68
 
49
69
  if((Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
@@ -62,13 +82,10 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
62
82
  basePlotLayoutAttributes, 'showlegend',
63
83
  legendReallyHasATrace && legendTraceCount > 1);
64
84
 
65
- if(showLegend === false && !containerIn.uirevision) return;
66
-
67
- var containerOut = Template.newContainer(layoutOut, 'legend');
85
+ // delete legend
86
+ if(showLegend === false) layoutOut.legend = undefined;
68
87
 
69
- function coerce(attr, dflt) {
70
- return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
71
- }
88
+ if(showLegend === false && !containerIn.uirevision) return;
72
89
 
73
90
  coerce('uirevision', layoutOut.uirevision);
74
91
 
@@ -96,8 +96,10 @@ function draw(gd, titleClass, options) {
96
96
 
97
97
  var elShouldExist = txt || editable;
98
98
 
99
+ var hColorbarMoveTitle;
99
100
  if(!group) {
100
101
  group = Lib.ensureSingle(fullLayout._infolayer, 'g', 'g-' + titleClass);
102
+ hColorbarMoveTitle = fullLayout._hColorbarMoveTitle;
101
103
  }
102
104
 
103
105
  var el = group.selectAll('text')
@@ -121,13 +123,17 @@ function draw(gd, titleClass, options) {
121
123
  function drawTitle(titleEl) {
122
124
  var transformVal;
123
125
 
126
+ if(!transform && hColorbarMoveTitle) {
127
+ transform = {};
128
+ }
129
+
124
130
  if(transform) {
125
131
  transformVal = '';
126
132
  if(transform.rotate) {
127
133
  transformVal += 'rotate(' + [transform.rotate, attributes.x, attributes.y] + ')';
128
134
  }
129
- if(transform.offset) {
130
- transformVal += strTranslate(0, transform.offset);
135
+ if(transform.offset || hColorbarMoveTitle) {
136
+ transformVal += strTranslate(0, (transform.offset || 0) - (hColorbarMoveTitle || 0));
131
137
  }
132
138
  } else {
133
139
  transformVal = null;
@@ -1719,7 +1719,7 @@ function cleanDeprecatedAttributeKeys(aobj) {
1719
1719
  if((key === 'title' || oldAxisTitleRegex.test(key) || colorbarRegex.test(key)) &&
1720
1720
  (typeof value === 'string' || typeof value === 'number')) {
1721
1721
  replace(key, key.replace('title', 'title.text'));
1722
- } else if(key.indexOf('titlefont') > -1) {
1722
+ } else if(key.indexOf('titlefont') > -1 && key.indexOf('grouptitlefont') === -1) {
1723
1723
  replace(key, key.replace('titlefont', 'title.font'));
1724
1724
  } else if(key.indexOf('titleposition') > -1) {
1725
1725
  replace(key, key.replace('titleposition', 'title.position'));
@@ -53,6 +53,9 @@ module.exports = function(opts) {
53
53
  description: '' + (opts.description || '') + ''
54
54
  };
55
55
 
56
+ if(opts.autoSize) attrs.size.dflt = 'auto';
57
+ if(opts.autoColor) attrs.color.dflt = 'auto';
58
+
56
59
  if(opts.arrayOk) {
57
60
  attrs.family.arrayOk = true;
58
61
  attrs.size.arrayOk = true;
@@ -309,6 +309,7 @@ module.exports = {
309
309
  'c) One trace is explicitly given with `showlegend: true`.'
310
310
  ].join(' ')
311
311
  },
312
+
312
313
  colorway: {
313
314
  valType: 'colorlist',
314
315
  dflt: colorAttrs.defaults,
@@ -1321,13 +1321,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
1321
1321
  );
1322
1322
 
1323
1323
  coerce('legendgroup');
1324
- var titleText = coerce('legendgrouptitle.text');
1325
- if(titleText) {
1326
- Lib.coerceFont(coerce, 'legendgrouptitle.font', Lib.extendFlat({}, layout.font, {
1327
- size: Math.round(layout.font.size * 1.1) // default to larger font size
1328
- }));
1329
- }
1330
-
1324
+ coerce('legendgrouptitle.text');
1331
1325
  coerce('legendrank');
1332
1326
 
1333
1327
  traceOut._dfltShowLegend = true;
@@ -1475,16 +1469,14 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {
1475
1469
 
1476
1470
  coerce('autotypenumbers');
1477
1471
 
1478
- var globalFont = Lib.coerceFont(coerce, 'font');
1479
-
1480
- coerce('title.text', layoutOut._dfltTitle.plot);
1472
+ var font = Lib.coerceFont(coerce, 'font');
1473
+ var fontSize = font.size;
1481
1474
 
1482
- Lib.coerceFont(coerce, 'title.font', {
1483
- family: globalFont.family,
1484
- size: Math.round(globalFont.size * 1.4),
1485
- color: globalFont.color
1486
- });
1475
+ Lib.coerceFont(coerce, 'title.font', Lib.extendFlat({}, font, {
1476
+ size: Math.round(fontSize * 1.4)
1477
+ }));
1487
1478
 
1479
+ coerce('title.text', layoutOut._dfltTitle.plot);
1488
1480
  coerce('title.xref');
1489
1481
  coerce('title.yref');
1490
1482
  coerce('title.x');
@@ -629,12 +629,14 @@ function calcTexttemplate(fullLayout, cd, index, xa, ya) {
629
629
  var trace = cd[0].trace;
630
630
  var texttemplate = Lib.castOption(trace, index, 'texttemplate');
631
631
  if(!texttemplate) return '';
632
+ var isHistogram = (trace.type === 'histogram');
632
633
  var isWaterfall = (trace.type === 'waterfall');
633
634
  var isFunnel = (trace.type === 'funnel');
635
+ var isHorizontal = trace.orientation === 'h';
634
636
 
635
637
  var pLetter, pAxis;
636
638
  var vLetter, vAxis;
637
- if(trace.orientation === 'h') {
639
+ if(isHorizontal) {
638
640
  pLetter = 'y';
639
641
  pAxis = ya;
640
642
  vLetter = 'x';
@@ -669,6 +671,11 @@ function calcTexttemplate(fullLayout, cd, index, xa, ya) {
669
671
  var pt = {};
670
672
  appendArrayPointValue(pt, trace, cdi.i);
671
673
 
674
+ if(isHistogram || pt.x === undefined) pt.x = isHorizontal ? obj.value : obj.label;
675
+ if(isHistogram || pt.y === undefined) pt.y = isHorizontal ? obj.label : obj.value;
676
+ if(isHistogram || pt.xLabel === undefined) pt.xLabel = isHorizontal ? obj.valueLabel : obj.labelLabel;
677
+ if(isHistogram || pt.yLabel === undefined) pt.yLabel = isHorizontal ? obj.labelLabel : obj.valueLabel;
678
+
672
679
  if(isWaterfall) {
673
680
  obj.delta = +cdi.rawS || cdi.s;
674
681
  obj.deltaLabel = formatNumber(obj.delta);
@@ -42,6 +42,18 @@ module.exports = extendFlat({
42
42
  yhoverformat: axisHoverFormat('y'),
43
43
  zhoverformat: axisHoverFormat('z', 1),
44
44
  hovertemplate: heatmapAttrs.hovertemplate,
45
+ texttemplate: extendFlat({}, heatmapAttrs.texttemplate, {
46
+ description: [
47
+ 'For this trace it only has an effect if `coloring` is set to *heatmap*.',
48
+ heatmapAttrs.texttemplate.description
49
+ ].join(' ')
50
+ }),
51
+ textfont: extendFlat({}, heatmapAttrs.textfont, {
52
+ description: [
53
+ 'For this trace it only has an effect if `coloring` is set to *heatmap*.',
54
+ heatmapAttrs.textfont.description
55
+ ].join(' ')
56
+ }),
45
57
  hoverongaps: heatmapAttrs.hoverongaps,
46
58
  connectgaps: extendFlat({}, heatmapAttrs.connectgaps, {
47
59
  description: [
@@ -7,6 +7,7 @@ var handlePeriodDefaults = require('../scatter/period_defaults');
7
7
  var handleConstraintDefaults = require('./constraint_defaults');
8
8
  var handleContoursDefaults = require('./contours_defaults');
9
9
  var handleStyleDefaults = require('./style_defaults');
10
+ var handleHeatmapLabelDefaults = require('../heatmap/label_defaults');
10
11
  var attributes = require('./attributes');
11
12
 
12
13
 
@@ -31,8 +32,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
31
32
 
32
33
  coerce('text');
33
34
  coerce('hovertext');
34
- coerce('hovertemplate');
35
35
  coerce('hoverongaps');
36
+ coerce('hovertemplate');
36
37
 
37
38
  var isConstraint = (coerce('contours.type') === 'constraint');
38
39
  coerce('connectgaps', Lib.isArray1D(traceOut.z));
@@ -43,4 +44,11 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
43
44
  handleContoursDefaults(traceIn, traceOut, coerce, coerce2);
44
45
  handleStyleDefaults(traceIn, traceOut, coerce, layout);
45
46
  }
47
+
48
+ if(
49
+ traceOut.contours &&
50
+ traceOut.contours.coloring === 'heatmap'
51
+ ) {
52
+ handleHeatmapLabelDefaults(coerce, layout);
53
+ }
46
54
  };
@@ -2,8 +2,10 @@
2
2
 
3
3
  var scatterAttrs = require('../scatter/attributes');
4
4
  var baseAttrs = require('../../plots/attributes');
5
+ var fontAttrs = require('../../plots/font_attributes');
5
6
  var axisHoverFormat = require('../../plots/cartesian/axis_format_attributes').axisHoverFormat;
6
7
  var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
8
+ var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
7
9
  var colorScaleAttrs = require('../../components/colorscale/attributes');
8
10
 
9
11
  var extendFlat = require('../../lib/extend').extendFlat;
@@ -116,6 +118,20 @@ module.exports = extendFlat({
116
118
  zhoverformat: axisHoverFormat('z', 1),
117
119
 
118
120
  hovertemplate: hovertemplateAttrs(),
121
+ texttemplate: texttemplateAttrs({
122
+ arrayOk: false,
123
+ editType: 'plot'
124
+ }, {
125
+ keys: ['x', 'y', 'z', 'text']
126
+ }),
127
+ textfont: fontAttrs({
128
+ editType: 'plot',
129
+ autoSize: true,
130
+ autoColor: true,
131
+ colorEditType: 'style',
132
+ description: 'Sets the text font.'
133
+ }),
134
+
119
135
  showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false})
120
136
  }, {
121
137
  transforms: undefined
@@ -3,6 +3,7 @@
3
3
  var Lib = require('../../lib');
4
4
 
5
5
  var handleXYZDefaults = require('./xyz_defaults');
6
+ var handleHeatmapLabelDefaults = require('./label_defaults');
6
7
  var handlePeriodDefaults = require('../scatter/period_defaults');
7
8
  var handleStyleDefaults = require('./style_defaults');
8
9
  var colorscaleDefaults = require('../../components/colorscale/defaults');
@@ -28,6 +29,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
28
29
  coerce('hovertext');
29
30
  coerce('hovertemplate');
30
31
 
32
+ handleHeatmapLabelDefaults(coerce, layout);
31
33
  handleStyleDefaults(traceIn, traceOut, coerce, layout);
32
34
 
33
35
  coerce('hoverongaps');
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ var Lib = require('../../lib');
4
+
5
+ module.exports = function handleHeatmapLabelDefaults(coerce, layout) {
6
+ coerce('texttemplate');
7
+
8
+ var fontDflt = Lib.extendFlat({}, layout.font, {
9
+ color: 'auto',
10
+ size: 'auto'
11
+ });
12
+ Lib.coerceFont(coerce, 'textfont', fontDflt);
13
+ };
@@ -4,9 +4,27 @@ var d3 = require('@plotly/d3');
4
4
  var tinycolor = require('tinycolor2');
5
5
 
6
6
  var Registry = require('../../registry');
7
+ var Drawing = require('../../components/drawing');
8
+ var Axes = require('../../plots/cartesian/axes');
7
9
  var Lib = require('../../lib');
10
+ var svgTextUtils = require('../../lib/svg_text_utils');
11
+ var formatLabels = require('../scatter/format_labels');
12
+ var Color = require('../../components/color');
13
+ var extractOpts = require('../../components/colorscale').extractOpts;
8
14
  var makeColorScaleFuncFromTrace = require('../../components/colorscale').makeColorScaleFuncFromTrace;
9
15
  var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
16
+ var alignmentConstants = require('../../constants/alignment');
17
+ var LINE_SPACING = alignmentConstants.LINE_SPACING;
18
+
19
+ var labelClass = 'heatmap-label';
20
+
21
+ function selectLabels(plotGroup) {
22
+ return plotGroup.selectAll('g.' + labelClass);
23
+ }
24
+
25
+ function removeLabels(plotGroup) {
26
+ selectLabels(plotGroup).remove();
27
+ }
10
28
 
11
29
  module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
12
30
  var xa = plotinfo.xaxis;
@@ -16,6 +34,8 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
16
34
  var plotGroup = d3.select(this);
17
35
  var cd0 = cd[0];
18
36
  var trace = cd0.trace;
37
+ var xGap = trace.xgap || 0;
38
+ var yGap = trace.ygap || 0;
19
39
 
20
40
  var z = cd0.z;
21
41
  var x = cd0.x;
@@ -31,7 +51,7 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
31
51
  var xrev = false;
32
52
  var yrev = false;
33
53
 
34
- var left, right, temp, top, bottom, i;
54
+ var left, right, temp, top, bottom, i, j, k;
35
55
 
36
56
  // TODO: if there are multiple overlapping categorical heatmaps,
37
57
  // or if we allow category sorting, then the categories may not be
@@ -112,6 +132,8 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
112
132
  if(isOffScreen) {
113
133
  var noImage = plotGroup.selectAll('image').data([]);
114
134
  noImage.exit().remove();
135
+
136
+ removeLabels(plotGroup);
115
137
  return;
116
138
  }
117
139
 
@@ -167,7 +189,7 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
167
189
  var gcount = 0;
168
190
  var bcount = 0;
169
191
 
170
- var xb, j, xi, v, row, c;
192
+ var xb, xi, v, row, c;
171
193
 
172
194
  function setColor(v, pixsize) {
173
195
  if(v !== undefined) {
@@ -278,8 +300,6 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
278
300
  } else { // zsmooth = false -> filling potentially large bricks works fastest with fillRect
279
301
  // gaps do not need to be exact integers, but if they *are* we will get
280
302
  // cleaner edges by rounding at least one edge
281
- var xGap = trace.xgap;
282
- var yGap = trace.ygap;
283
303
  var xGapLeft = Math.floor(xGap / 2);
284
304
  var yGapTop = Math.floor(yGap / 2);
285
305
 
@@ -332,6 +352,187 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) {
332
352
  y: top,
333
353
  'xlink:href': canvas.toDataURL('image/png')
334
354
  });
355
+
356
+ removeLabels(plotGroup);
357
+
358
+ var texttemplate = trace.texttemplate;
359
+ if(texttemplate) {
360
+ // dummy axis for formatting the z value
361
+ var cOpts = extractOpts(trace);
362
+ var dummyAx = {
363
+ type: 'linear',
364
+ range: [cOpts.min, cOpts.max],
365
+ _separators: xa._separators,
366
+ _numFormat: xa._numFormat
367
+ };
368
+
369
+ var aHistogram2dContour = trace.type === 'histogram2dcontour';
370
+ var aContour = trace.type === 'contour';
371
+ var iStart = aContour ? 1 : 0;
372
+ var iStop = aContour ? m - 1 : m;
373
+ var jStart = aContour ? 1 : 0;
374
+ var jStop = aContour ? n - 1 : n;
375
+
376
+ var textData = [];
377
+ for(i = iStart; i < iStop; i++) {
378
+ var yVal;
379
+ if(aContour) {
380
+ yVal = cd0.y[i];
381
+ } else if(aHistogram2dContour) {
382
+ if(i === 0 || i === m - 1) continue;
383
+ yVal = cd0.y[i];
384
+ } else if(cd0.yCenter) {
385
+ yVal = cd0.yCenter[i];
386
+ } else {
387
+ if(i + 1 === m && cd0.y[i + 1] === undefined) continue;
388
+ yVal = (cd0.y[i] + cd0.y[i + 1]) / 2;
389
+ }
390
+
391
+ var _y = Math.round(ya.c2p(yVal));
392
+ if(0 > _y || _y > ya._length) continue;
393
+
394
+ for(j = jStart; j < jStop; j++) {
395
+ var xVal;
396
+ if(aContour) {
397
+ xVal = cd0.x[j];
398
+ } else if(aHistogram2dContour) {
399
+ if(j === 0 || j === n - 1) continue;
400
+ xVal = cd0.x[j];
401
+ } else if(cd0.xCenter) {
402
+ xVal = cd0.xCenter[j];
403
+ } else {
404
+ if(j + 1 === n && cd0.x[j + 1] === undefined) continue;
405
+ xVal = (cd0.x[j] + cd0.x[j + 1]) / 2;
406
+ }
407
+
408
+ var _x = Math.round(xa.c2p(xVal));
409
+ if(0 > _x || _x > xa._length) continue;
410
+
411
+ var obj = formatLabels({
412
+ x: xVal,
413
+ y: yVal
414
+ }, trace, gd._fullLayout);
415
+
416
+ obj.x = xVal;
417
+ obj.y = yVal;
418
+
419
+ var zVal = cd0.z[i][j];
420
+ if(zVal === undefined) {
421
+ obj.z = '';
422
+ obj.zLabel = '';
423
+ } else {
424
+ obj.z = zVal;
425
+ obj.zLabel = Axes.tickText(dummyAx, zVal, 'hover').text;
426
+ }
427
+
428
+ var theText = cd0.text && cd0.text[i] && cd0.text[i][j];
429
+ if(theText === undefined || theText === false) theText = '';
430
+ obj.text = theText;
431
+
432
+ var _t = Lib.texttemplateString(texttemplate, obj, gd._fullLayout._d3locale, obj, trace._meta || {});
433
+ if(!_t) continue;
434
+
435
+ var lines = _t.split('<br>');
436
+ var nL = lines.length;
437
+ var nC = 0;
438
+ for(k = 0; k < nL; k++) {
439
+ nC = Math.max(nC, lines[k].length);
440
+ }
441
+
442
+ textData.push({
443
+ l: nL, // number of lines
444
+ c: nC, // maximum number of chars in a line
445
+ t: _t, // text
446
+ x: _x,
447
+ y: _y,
448
+ z: zVal
449
+ });
450
+ }
451
+ }
452
+
453
+ var font = trace.textfont;
454
+ var fontFamily = font.family;
455
+ var fontSize = font.size;
456
+ var globalFontSize = gd._fullLayout.font.size;
457
+
458
+ if(!fontSize || fontSize === 'auto') {
459
+ var minW = Infinity;
460
+ var minH = Infinity;
461
+ var maxL = 0;
462
+ var maxC = 0;
463
+
464
+ for(k = 0; k < textData.length; k++) {
465
+ var d = textData[k];
466
+ maxL = Math.max(maxL, d.l);
467
+ maxC = Math.max(maxC, d.c);
468
+
469
+ if(k < textData.length - 1) {
470
+ var nextD = textData[k + 1];
471
+ var dx = Math.abs(nextD.x - d.x);
472
+ var dy = Math.abs(nextD.y - d.y);
473
+
474
+ if(dx) minW = Math.min(minW, dx);
475
+ if(dy) minH = Math.min(minH, dy);
476
+ }
477
+ }
478
+
479
+ if(
480
+ !isFinite(minW) ||
481
+ !isFinite(minH)
482
+ ) {
483
+ fontSize = globalFontSize;
484
+ } else {
485
+ minW -= xGap;
486
+ minH -= yGap;
487
+
488
+ minW /= maxC;
489
+ minH /= maxL;
490
+
491
+ minW /= LINE_SPACING / 2;
492
+ minH /= LINE_SPACING;
493
+
494
+ fontSize = Math.min(
495
+ Math.floor(minW),
496
+ Math.floor(minH),
497
+ globalFontSize
498
+ );
499
+ }
500
+ }
501
+ if(fontSize <= 0 || !isFinite(fontSize)) return;
502
+
503
+ var xFn = function(d) { return d.x; };
504
+ var yFn = function(d) {
505
+ return d.y - fontSize * ((d.l * LINE_SPACING) / 2 - 1);
506
+ };
507
+
508
+ var labels = selectLabels(plotGroup).data(textData);
509
+
510
+ labels
511
+ .enter()
512
+ .append('g')
513
+ .classed(labelClass, 1)
514
+ .append('text')
515
+ .attr('text-anchor', 'middle')
516
+ .each(function(d) {
517
+ var thisLabel = d3.select(this);
518
+
519
+ var fontColor = font.color;
520
+ if(!fontColor || fontColor === 'auto') {
521
+ fontColor = Color.contrast(
522
+ 'rgba(' +
523
+ sclFunc(d.z).join() +
524
+ ')'
525
+ );
526
+ }
527
+
528
+ thisLabel
529
+ .attr('data-notex', 1)
530
+ .call(svgTextUtils.positionText, xFn(d), yFn(d))
531
+ .call(Drawing.font, fontFamily, fontSize, fontColor)
532
+ .text(d.t)
533
+ .call(svgTextUtils.convertToTspans, gd);
534
+ });
535
+ }
335
536
  });
336
537
  };
337
538