diff --git a/src/traces/indicator/attributes.js b/src/traces/indicator/attributes.js index cf18febfa5b..c8288681ba2 100644 --- a/src/traces/indicator/attributes.js +++ b/src/traces/indicator/attributes.js @@ -8,9 +8,6 @@ 'use strict'; -// var plotAttrs = require('../../plots/attributes'); -// var domainAttrs = require('../../plots/domain').attributes; - var extendFlat = require('../../lib/extend').extendFlat; var extendDeep = require('../../lib/extend').extendDeep; var overrideAll = require('../../plot_api/edit_types').overrideAll; @@ -102,7 +99,13 @@ module.exports = { editType: 'calc', role: 'info', flags: ['number', 'delta', 'gauge'], - dflt: 'number' + dflt: 'number', + description: [ + 'Determines how the value is displayed on the graph.', + '`number` displays the value numerically in text.', + '`delta` displays the difference to a reference value in text.', + 'Finally, `gauge` displays the value graphically on an axis.', + ].join(' ') }, value: { valType: 'number', @@ -189,6 +192,15 @@ module.exports = { 'Set the font used to display main number' ].join(' ') }), + prefix: { + valType: 'string', + dflt: '', + role: 'info', + editType: 'plot', + description: [ + 'Sets a prefix appearing before the number.' + ].join(' ') + }, suffix: { valType: 'string', dflt: '', @@ -206,7 +218,8 @@ module.exports = { role: 'info', editType: 'calc', description: [ - 'Sets the reference value to compute the delta.' + 'Sets the reference value to compute the delta.', + 'By default, it is set to the current value.' ].join(' ') }, position: { @@ -327,6 +340,9 @@ module.exports = { description: 'Sets the width (in px) of the border enclosing the gauge.' }, axis: overrideAll({ + visible: extendDeep({}, axesAttrs.visible, { + dflt: true + }), // tick and title properties named and function exactly as in axes tickmode: axesAttrs.tickmode, nticks: axesAttrs.nticks, diff --git a/src/traces/indicator/calc.js b/src/traces/indicator/calc.js index c86dc06ed9f..30e9a891a8c 100644 --- a/src/traces/indicator/calc.js +++ b/src/traces/indicator/calc.js @@ -13,9 +13,6 @@ function calc(gd, trace) { var cd = []; - // var singleValue = len === 1; - // var lastReading = trace.values[len - 1]; - // var secondLastReading = singleValue ? lastReading : trace.values[len - 2]; var lastReading = trace.value; var secondLastReading = trace.delta ? trace.delta.reference : trace._lastValue || trace.value; cd[0] = { diff --git a/src/traces/indicator/defaults.js b/src/traces/indicator/defaults.js index cfe011686e8..972600586f9 100644 --- a/src/traces/indicator/defaults.js +++ b/src/traces/indicator/defaults.js @@ -37,17 +37,18 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { coerce('vmax', 1.5 * traceOut.value); // Number attributes - var auto = []; + var auto = new Array(2); var bignumberFontSize; if(traceOut._hasNumber) { coerce('number.valueformat'); coerce('number.font.color', layout.font.color); coerce('number.font.family', layout.font.family); - coerce('number.font.size', 'auto'); - if(traceOut.number.font.size === 'auto') { + coerce('number.font.size'); + if(!traceOut.number.font.size) { traceOut.number.font.size = cn.defaultNumberFontSize; auto[0] = true; } + coerce('number.prefix'); coerce('number.suffix'); bignumberFontSize = traceOut.number.font.size; } @@ -57,8 +58,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { if(traceOut._hasDelta) { coerce('delta.font.color', layout.font.color); coerce('delta.font.family', layout.font.family); - coerce('delta.font.size', 'auto'); - if(traceOut.delta.font.size === 'auto') { + coerce('delta.font.size'); + if(!traceOut.delta.font.size) { traceOut.delta.font.size = (traceOut._hasNumber ? 0.5 : 1) * (bignumberFontSize || cn.defaultNumberFontSize); auto[1] = true; } @@ -133,6 +134,7 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { axisIn = {}; if(gaugeIn) axisIn = gaugeIn.axis || {}; axisOut = Template.newContainer(gaugeOut, 'axis'); + coerceGaugeAxis('visible'); handleTickValueDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear'); var opts = {outerTicks: false, font: layout.font}; diff --git a/src/traces/indicator/plot.js b/src/traces/indicator/plot.js index 116ba597693..16caaf81871 100644 --- a/src/traces/indicator/plot.js +++ b/src/traces/indicator/plot.js @@ -22,6 +22,7 @@ var handleAxisDefaults = require('../../plots/cartesian/axis_defaults'); var handleAxisPositionDefaults = require('../../plots/cartesian/position_defaults'); var axisLayoutAttrs = require('../../plots/cartesian/layout_attributes'); +var Color = require('../../components/color'); var anchor = { 'left': 'start', 'center': 'middle', @@ -86,7 +87,7 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb if(!hasGauge) { numbersX = size.l + position[numbersAlign] * size.w; numbersScaler = function(el) { - return fitTextInsideBox(el, 0.9 * size.w, 0.9 * size.h); + return fitTextInsideBox(el, size.w, size.h); }; } else { if(isAngular) { @@ -142,10 +143,9 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb } // Prepare angular gauge layers - var data = cd.filter(function() {return isAngular;}); - var angularGauge = plotGroup.selectAll('g.angular').data(data); + var angularGauge = plotGroup.selectAll('g.angular').data(isAngular ? cd : []); angularGauge.exit().remove(); - var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(data); + var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(isAngular ? cd : []); angularaxisLayer.exit().remove(); var gaugeOpts = { @@ -163,10 +163,9 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb if(isAngular) drawAngularGauge(gd, plotGroup, cd, gaugeOpts); // Prepare bullet layers - data = cd.filter(function() {return isBullet;}); - var bulletGauge = plotGroup.selectAll('g.bullet').data(data); + var bulletGauge = plotGroup.selectAll('g.bullet').data(isBullet ? cd : []); bulletGauge.exit().remove(); - var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(data); + var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(isBullet ? cd : []); bulletaxisLayer.exit().remove(); gaugeOpts = { @@ -202,8 +201,12 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb if(hasGauge) { if(isAngular) { // position above axis ticks/labels - var bBox = Drawing.bBox(angularaxisLayer.node()); - titleY = (bBox.top - titlePadding) - titlebBox.bottom; + if(trace.gauge.axis.visible) { + var bBox = Drawing.bBox(angularaxisLayer.node()); + titleY = (bBox.top - titlePadding) - titlebBox.bottom; + } else { + titleY = size.t + size.h / 2 - radius / 2 - titlebBox.bottom - titlePadding; + } } if(isBullet) { // position outside domain @@ -244,7 +247,7 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) { bulletaxis.enter().append('g') .classed('bulletaxis', true) .classed('crisp', true); - bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path').remove(); + bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path,text').remove(); // Draw bullet var bulletHeight = size.h; // use all vertical domain @@ -288,16 +291,16 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) { // Draw bullet background, steps var boxes = [gaugeBg].concat(trace.gauge.steps); - var targetBullet = bullet.selectAll('g.targetBullet').data(boxes); - targetBullet.enter().append('g').classed('targetBullet', true).append('rect'); + var targetBullet = bullet.selectAll('g.target-bullet').data(boxes); + targetBullet.enter().append('g').classed('target-bullet', true).append('rect'); targetBullet.select('rect') .call(drawRect) .call(styleShape); targetBullet.exit().remove(); // Draw value bar with transitions - var fgBullet = bullet.selectAll('g.fgBullet').data([trace.gauge.value]); - fgBullet.enter().append('g').classed('fgBullet', true).append('rect'); + var fgBullet = bullet.selectAll('g.fg-bullet').data([trace.gauge.value]); + fgBullet.enter().append('g').classed('fg-bullet', true).append('rect'); fgBullet.select('rect') .attr('height', innerBulletHeight) .attr('y', (bulletHeight - innerBulletHeight) / 2) @@ -324,12 +327,12 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) { .attr('x2', ax.c2p(trace.gauge.threshold.value)) .attr('y1', (1 - trace.gauge.threshold.thickness) / 2 * bulletHeight) .attr('y2', (1 - (1 - trace.gauge.threshold.thickness) / 2) * bulletHeight) - .style('stroke', trace.gauge.threshold.line.color) + .call(Color.stroke, trace.gauge.threshold.line.color) .style('stroke-width', trace.gauge.threshold.line.width); threshold.exit().remove(); - var bulletOutline = bullet.selectAll('g.bulletOutline').data([gaugeOutline]); - bulletOutline.enter().append('g').classed('bulletOutline', true).append('rect'); + var bulletOutline = bullet.selectAll('g.bullet-outline').data([gaugeOutline]); + bulletOutline.enter().append('g').classed('bullet-outline', true).append('rect'); bulletOutline.select('rect') .call(drawRect) .call(styleShape); @@ -388,12 +391,12 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) { angularaxisLayer.enter().append('g') .classed('angularaxis', true) .classed('crisp', true); - angularaxisLayer.selectAll('g.' + 'angularaxis' + 'tick,path').remove(); + angularaxisLayer.selectAll('g.' + 'xangularaxis' + 'tick,path,text').remove(); ax = mockAxis(gd, opts); ax.type = 'linear'; ax.range = [trace.vmin, trace.vmax]; - ax._id = 'x'; // or 'y', but I don't think this makes a difference here + ax._id = 'xangularaxis'; // or 'y', but I don't think this makes a difference here ax.setScale(); // 't'ick to 'g'eometric radians is used all over the place here @@ -426,17 +429,20 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) { return -0.5 * (1 + Math.sin(rad)) * h; }; var _transFn = function(rad) { - return strTranslate(gaugePosition[0] + radius * Math.cos(rad), gaugePosition[1] - radius * Math.sin(rad)); + return strTranslate( + gaugePosition[0] + radius * Math.cos(rad), + gaugePosition[1] - radius * Math.sin(rad) + ); }; transFn = function(d) { return _transFn(t2g(d)); }; var transFn2 = function(d) { var rad = t2g(d); - return _transFn(rad) + strRotate(-rad2deg(rad)); + return _transFn(rad) + 'rotate(' + -rad2deg(rad) + ')'; }; vals = Axes.calcTicks(ax); - tickSign; + tickSign = Axes.getTickSigns(ax)[2]; if(ax.visible) { tickSign = ax.ticks === 'inside' ? -1 : 1; var pad = (ax.linewidth || 1) / 2; @@ -444,8 +450,7 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) { vals: vals, layer: angularaxisLayer, path: 'M' + (tickSign * pad) + ',0h' + (tickSign * ax.ticklen), - transFn: transFn2, - crips: true + transFn: transFn2 }); Axes.drawLabels(gd, ax, { vals: vals, @@ -470,14 +475,14 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) { // Draw background + steps var arcs = [gaugeBg].concat(trace.gauge.steps); if(v) arcs.push(thresholdArc); - var targetArc = angularGauge.selectAll('g.targetArc').data(arcs); - targetArc.enter().append('g').classed('targetArc', true).append('path'); + var targetArc = angularGauge.selectAll('g.target-arc').data(arcs); + targetArc.enter().append('g').classed('target-arc', true).append('path'); targetArc.select('path').call(drawArc).call(styleShape); targetArc.exit().remove(); // Draw foreground with transition var valueArcPath = arcPathGenerator(trace.gauge.value.thickness); - var fgArc = angularGauge.selectAll('g.fgArc').data([trace.gauge.value]); - fgArc.enter().append('g').classed('fgArc', true).append('path'); + var fgArc = angularGauge.selectAll('g.fg-arc').data([trace.gauge.value]); + fgArc.enter().append('g').classed('fgarc', true).append('path'); var fgArcPath = fgArc.select('path'); if(hasTransition) { fgArcPath @@ -493,8 +498,8 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) { } fgArcPath.call(styleShape); fgArc.exit().remove(); - var gaugeBorder = angularGauge.selectAll('g.gaugeOutline').data([gaugeOutline]); - gaugeBorder.enter().append('g').classed('gaugeOutline', true).append('path'); + var gaugeBorder = angularGauge.selectAll('g.gauge-outline').data([gaugeOutline]); + gaugeBorder.enter().append('g').classed('gauge-outline', true).append('path'); gaugeBorder.select('path').call(drawArc).call(styleShape); gaugeBorder.exit().remove(); } @@ -564,7 +569,7 @@ function drawNumbers(gd, plotGroup, cd, opts) { var bignumberAx = mockAxis(gd, {tickformat: trace.number.valueformat}); var fmt = function(v) { return Axes.tickText(bignumberAx, v).text;}; var bignumberSuffix = trace.number.suffix; - if(bignumberSuffix) bignumberSuffix = ' ' + bignumberSuffix; + var bignumberPrefix = trace.number.prefix; var number = numbers.select('tspan.number'); number @@ -583,11 +588,11 @@ function drawNumbers(gd, plotGroup, cd, opts) { var that = d3.select(this); var interpolator = d3.interpolateNumber(cd[0].lastY, cd[0].y); return function(t) { - that.text(fmt(interpolator(t)) + bignumberSuffix); + that.text(bignumberPrefix + fmt(interpolator(t)) + bignumberSuffix); }; }); } else { - number.text(fmt(cd[0].y) + bignumberSuffix); + number.text(bignumberPrefix + fmt(cd[0].y) + bignumberSuffix); } } @@ -610,7 +615,7 @@ function drawNumbers(gd, plotGroup, cd, opts) { var delta = numbers.select('tspan.delta'); delta .call(Drawing.font, trace.delta.font) - .style('fill', deltaFill) + .each(function(d) { Color.fill(d3.select(this), deltaFill(d));}) .attr('x', deltaX) .attr('dy', deltaDy); @@ -669,8 +674,8 @@ function drawNumbers(gd, plotGroup, cd, opts) { // Apply fill, stroke, stroke-width to SVG shape function styleShape(p) { p - .style('fill', function(d) { return d.color;}) - .style('stroke', function(d) { return d.line.color;}) + .each(function(d) { Color.stroke(d3.select(this), d.line.color);}) + .each(function(d) { Color.fill(d3.select(this), d.color);}) .style('stroke-width', function(d) { return d.line.width;}); } @@ -690,6 +695,7 @@ function mockAxis(gd, opts, zrange) { var fullLayout = gd._fullLayout; var axisIn = { + visible: opts.visible, type: 'linear', ticks: 'outside', range: zrange, @@ -743,10 +749,6 @@ function strTranslate(x, y) { return 'translate(' + x + ',' + y + ')'; } -function strRotate(angle) { - return 'rotate(' + angle + ')'; -} - function fitTextInsideBox(el, width, height) { // compute scaling ratio to have text fit within specified width and height var textBB = Drawing.bBox(el.node()); @@ -761,28 +763,3 @@ function fitTextInsideCircle(el, radius) { var ratio = radius / elRadius; return [ratio, textBB, radius]; } - -// Draw gauge's min and max in text -// var minText = gauge.selectAll('text.min').data(cd); -// minText.enter().append('text').classed('min', true); -// minText -// .call(Drawing.font, trace.number.font) -// .style('font-size', gaugeFontSize) -// .attr({ -// x: - (innerRadius + radius) / 2, -// y: gaugeFontSize, -// 'text-anchor': 'middle' -// }) -// .text(fmt(trace.vmin)); -// -// var maxText = gauge.selectAll('text.max').data(cd); -// maxText.enter().append('text').classed('max', true); -// maxText -// .call(Drawing.font, trace.number.font) -// .style('font-size', gaugeFontSize) -// .attr({ -// x: (innerRadius + radius) / 2, -// y: gaugeFontSize, -// 'text-anchor': 'middle' -// }) -// .text(fmt(trace.vmax)); diff --git a/test/image/baselines/indicator_datacard.png b/test/image/baselines/indicator_datacard.png index 025060feaea..27378fcf290 100644 Binary files a/test/image/baselines/indicator_datacard.png and b/test/image/baselines/indicator_datacard.png differ diff --git a/test/image/baselines/indicator_datacard2.png b/test/image/baselines/indicator_datacard2.png index 581a18b829d..22648e8179b 100644 Binary files a/test/image/baselines/indicator_datacard2.png and b/test/image/baselines/indicator_datacard2.png differ diff --git a/test/image/mocks/indicator_bignumber.json b/test/image/mocks/indicator_bignumber.json index ed8843b93fd..59876ba35cf 100644 --- a/test/image/mocks/indicator_bignumber.json +++ b/test/image/mocks/indicator_bignumber.json @@ -19,7 +19,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 450 }, { "domain": { @@ -36,7 +35,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 350 }, { "domain": { @@ -53,7 +51,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 430 }, { "domain": { @@ -71,7 +68,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 450 }, { "domain": { @@ -88,7 +84,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 350 }, { "domain": { @@ -105,7 +100,6 @@ "gauge": { "bgcolor": "rgba(255, 255, 255, 0.25)" }, - "max": 500, "value": 450 } ], diff --git a/test/image/mocks/indicator_datacard.json b/test/image/mocks/indicator_datacard.json index 42f5503e7c1..f2a34579967 100644 --- a/test/image/mocks/indicator_datacard.json +++ b/test/image/mocks/indicator_datacard.json @@ -5,7 +5,7 @@ "mode": "number+delta", "number": { "align": "middle", - "suffix": "km/h" + "suffix": " km/h" }, "value": 43, "delta": { @@ -18,7 +18,7 @@ "mode": "number+delta", "number": { "align": "middle", - "suffix": "km/h" + "suffix": " km/h" }, "value": 43, "delta": { @@ -31,7 +31,7 @@ "mode": "number+delta", "number": { "align": "middle", - "suffix": "km/h" + "suffix": " km/h" }, "value": 43, "delta": { @@ -44,7 +44,7 @@ "mode": "number+delta", "number": { "align": "middle", - "suffix": "km/h" + "suffix": " km/h" }, "value": 43, "delta": { diff --git a/test/image/mocks/indicator_datacard2.json b/test/image/mocks/indicator_datacard2.json index bbb0237e9d4..c9a53809e9c 100644 --- a/test/image/mocks/indicator_datacard2.json +++ b/test/image/mocks/indicator_datacard2.json @@ -5,7 +5,7 @@ "mode": "number+delta", "align": "left", "number": { - "suffix": "km/h", + "suffix": " km/h", "font": {"size": 20} }, "value": 43, @@ -19,7 +19,8 @@ "mode": "number+delta", "align": "right", "number": { - "suffix": "km/h", + "prefix": "prefix: ", + "suffix": " km/h", "font": {"size": 20} }, "value": 43, @@ -33,7 +34,7 @@ "mode": "number+delta", "align": "left", "number": { - "suffix": "km/h", + "suffix": " km/h", "font": {"size": 20} }, "value": 43, @@ -47,7 +48,7 @@ "mode": "number+delta", "align": "right", "number": { - "suffix": "km/h", + "suffix": " km/h", "font": {"size": 20} }, "value": 43, diff --git a/test/jasmine/tests/indicator_test.js b/test/jasmine/tests/indicator_test.js index de1b71d174e..44eb99d442c 100644 --- a/test/jasmine/tests/indicator_test.js +++ b/test/jasmine/tests/indicator_test.js @@ -7,17 +7,10 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var delay = require('../assets/delay'); var failTest = require('../assets/fail_test'); -// var click = require('../assets/click'); -// var getClientPosition = require('../assets/get_client_position'); -// var mouseEvent = require('../assets/mouse_event'); var supplyAllDefaults = require('../assets/supply_defaults'); +// var calc = require('@src/traces/indicator/calc').calc; var indicatorAttrs = require('@src/traces/indicator/attributes.js'); var cn = require('@src/traces/indicator/constants.js'); -// var rgb = require('../../../src/components/color').rgb; - -// var customAssertions = require('../assets/custom_assertions'); -// var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; -// var assertHoverLabelContent = customAssertions.assertHoverLabelContent; describe('Indicator defaults', function() { function _supply(trace, layout) { @@ -56,6 +49,11 @@ describe('Indicator defaults', function() { expect(out.delta.valueformat).toBe('2%'); }); + it('defaults delta.reference to current value', function() { + var out = _supply({type: 'indicator', mode: 'delta', value: 1}); + expect(out.delta.reference).toBe(1); + }); + // text alignment ['number'].forEach(function(mode) { it('aligns to center', function() { @@ -175,11 +173,11 @@ describe('Indicator plot', function() { return Plotly.restyle(gd, 'value', [1E6]); }) .then(function() { - checkNumbersScale(0.7, 'should scale down'); + checkNumbersScale(0.8, 'should scale down'); return Plotly.restyle(gd, 'value', [1]); }) .then(function() { - checkNumbersScale(0.7, 'should not scale up'); + checkNumbersScale(0.8, 'should not scale up'); }) .catch(failTest) .then(done); @@ -243,7 +241,7 @@ describe('Indicator plot', function() { Plotly.newPlot(gd, [{ type: 'indicator', mode: 'number', - number: {suffix: 'potatoes'}, + number: {suffix: ' potatoes'}, value: 220, }]) .then(function() { @@ -252,6 +250,20 @@ describe('Indicator plot', function() { .catch(failTest) .then(done); }); + + it('supports prefix', function(done) { + Plotly.newPlot(gd, [{ + type: 'indicator', + mode: 'number', + number: {prefix: 'Speed: '}, + value: 220, + }]) + .then(function() { + assertContent('Speed: 220'); + }) + .catch(failTest) + .then(done); + }); }); describe('delta', function() { @@ -417,22 +429,30 @@ describe('Indicator animations', function() { }); afterEach(destroyGraphDiv); - it('should be able to transition via `Plotly.react`', function(done) { - var mock = {data: [{type: 'indicator', value: 100}], layout: {}}; - mock.layout.transition = {duration: 200}; + [['number', ''], ['delta', ''], ['number+delta', ''], + ['gauge', 'angular'], ['gauge', 'bullet']].forEach(function(comb) { + it('should transition via `Plotly.react` in mode ' + comb[0] + ', ' + comb[1], function(done) { + var mock = {data: [{ + type: 'indicator', + mode: comb[0], + gauge: {shape: comb[1]}, + value: 100 + }], layout: {}}; + mock.layout.transition = {duration: 200}; - spyOn(Plots, 'transitionFromReact').and.callThrough(); + spyOn(Plots, 'transitionFromReact').and.callThrough(); - Plotly.plot(gd, mock) - .then(function() { - gd.data[0].value = '400'; - return Plotly.react(gd, gd.data, gd.layout); - }) - .then(delay(300)) - .then(function() { - expect(Plots.transitionFromReact).toHaveBeenCalledTimes(1); - }) - .catch(failTest) - .then(done); + Plotly.plot(gd, mock) + .then(function() { + gd.data[0].value = '400'; + return Plotly.react(gd, gd.data, gd.layout); + }) + .then(delay(300)) + .then(function() { + expect(Plots.transitionFromReact).toHaveBeenCalledTimes(1); + }) + .catch(failTest) + .then(done); + }); }); }); diff --git a/test/jasmine/tests/snapshot_test.js b/test/jasmine/tests/snapshot_test.js index 62743768fca..6c4a4dc3fb0 100644 --- a/test/jasmine/tests/snapshot_test.js +++ b/test/jasmine/tests/snapshot_test.js @@ -255,6 +255,35 @@ describe('Plotly.Snapshot', function() { expect((actual || '').substr(0, 6)).toBe('url(\"#', msg); } + it('- tspans', function(done) { + var fontFamily = '"Times New Roman"'; + Plotly.newPlot(gd, [{ + type: 'indicator', + mode: 'delta+number', + value: 10 + }], {font: {family: fontFamily}}) + .then(function() { + d3.selectAll('tspan').each(function() { + expect(this.style.fontFamily).toEqual(fontFamily); + }); + + return Plotly.Snapshot.toSVG(gd); + }) + .then(function(svg) { + var svgDOM = parser.parseFromString(svg, 'image/svg+xml'); + var i; + + var tspanElements = svgDOM.getElementsByTagName('tspan'); + expect(tspanElements.length).toEqual(2); + + for(i = 0; i < tspanElements.length; i++) { + expect(tspanElements[i].style.fontFamily).toEqual(fontFamily); + } + }) + .catch(failTest) + .then(done); + }); + it('- marker-gradient case', function(done) { Plotly.plot(gd, [{ y: [1, 2, 1],