diff --git a/dist/plotly-locale-en-us.js b/dist/plotly-locale-en-us.js new file mode 100644 index 00000000000..b091f1616d2 --- /dev/null +++ b/dist/plotly-locale-en-us.js @@ -0,0 +1 @@ +Plotly.register({moduleType:"locale",name:"en-US",dictionary:{"Click to enter Colorscale title":"Click to enter Colorscale title"}}); \ No newline at end of file diff --git a/dist/plotly-locale-en.js b/dist/plotly-locale-en.js new file mode 100644 index 00000000000..17c53abca69 --- /dev/null +++ b/dist/plotly-locale-en.js @@ -0,0 +1 @@ +Plotly.register({moduleType:"locale",name:"en",dictionary:{"Click to enter Colorscale title":"Click to enter Colourscale title"}}); \ No newline at end of file diff --git a/dist/translation-keys.txt b/dist/translation-keys.txt new file mode 100644 index 00000000000..42154ee4f3b --- /dev/null +++ b/dist/translation-keys.txt @@ -0,0 +1,56 @@ +Autoscale // components/modebar/buttons.js:139 +Box Select // components/modebar/buttons.js:103 +Click to enter Colorscale title // plots/plots.js:437 +Click to enter Component A title // plots/ternary/ternary.js:386 +Click to enter Component B title // plots/ternary/ternary.js:400 +Click to enter Component C title // plots/ternary/ternary.js:411 +Click to enter Plot title // plot_api/plot_api.js:579 +Click to enter X axis title // plots/plots.js:435 +Click to enter Y axis title // plots/plots.js:436 +Compare data on hover // components/modebar/buttons.js:167 +Double-click on legend to isolate one trace // components/legend/handle_click.js:90 +Double-click to zoom back out // plots/cartesian/dragbox.js:299 +Download plot as a png // components/modebar/buttons.js:52 +Edit in Chart Studio // components/modebar/buttons.js:76 +IE only supports svg. Changing format to svg. // components/modebar/buttons.js:60 +Lasso Select // components/modebar/buttons.js:112 +Orbital rotation // components/modebar/buttons.js:279 +Pan // components/modebar/buttons.js:94 +Produced with Plotly // components/modebar/modebar.js:256 +Reset // components/modebar/buttons.js:432 +Reset axes // components/modebar/buttons.js:148 +Reset camera to default // components/modebar/buttons.js:314 +Reset camera to last save // components/modebar/buttons.js:322 +Reset view // components/modebar/buttons.js:583 +Reset views // components/modebar/buttons.js:529 +Show closest data on hover // components/modebar/buttons.js:157 +Snapshot succeeded // components/modebar/buttons.js:66 +Sorry, there was a problem downloading your snapshot! // components/modebar/buttons.js:69 +Taking snapshot - this may take a few seconds // components/modebar/buttons.js:57 +Toggle Spike Lines // components/modebar/buttons.js:548 +Toggle show closest data on hover // components/modebar/buttons.js:353 +Turntable rotation // components/modebar/buttons.js:288 +Zoom // components/modebar/buttons.js:85 +Zoom in // components/modebar/buttons.js:121 +Zoom out // components/modebar/buttons.js:130 +close: // traces/ohlc/transform.js:139 +high: // traces/ohlc/transform.js:137 +incoming flow count: // traces/sankey/plot.js:142 +kde: // traces/violin/calc.js:73 +lat: // traces/scattergeo/calc.js:48 +lon: // traces/scattergeo/calc.js:49 +low: // traces/ohlc/transform.js:138 +lower fence: // traces/box/calc.js:134 +max: // traces/box/calc.js:132 +mean ± σ: // traces/box/calc.js:133 +mean: // traces/box/calc.js:133 +median: // traces/box/calc.js:128 +min: // traces/box/calc.js:129 +open: // traces/ohlc/transform.js:136 +outgoing flow count: // traces/sankey/plot.js:143 +q1: // traces/box/calc.js:130 +q3: // traces/box/calc.js:131 +source: // traces/sankey/plot.js:140 +target: // traces/sankey/plot.js:141 +trace // plots/plots.js:439 +upper fence: // traces/box/calc.js:135 \ No newline at end of file diff --git a/lib/index-basic.js b/lib/index-basic.js index 4c837e413ad..6bf47b0d84a 100644 --- a/lib/index-basic.js +++ b/lib/index-basic.js @@ -15,4 +15,10 @@ Plotly.register([ require('./pie') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-cartesian.js b/lib/index-cartesian.js index 5818a717748..6dc20783571 100644 --- a/lib/index-cartesian.js +++ b/lib/index-cartesian.js @@ -23,4 +23,10 @@ Plotly.register([ require('./violin') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-finance.js b/lib/index-finance.js index 4759344b760..f53dee82c9f 100644 --- a/lib/index-finance.js +++ b/lib/index-finance.js @@ -18,4 +18,10 @@ Plotly.register([ require('./candlestick') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-geo.js b/lib/index-geo.js index 2283f1f0489..40dec26e9e9 100644 --- a/lib/index-geo.js +++ b/lib/index-geo.js @@ -15,4 +15,10 @@ Plotly.register([ require('./choropleth') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-gl2d.js b/lib/index-gl2d.js index 9c24ec21267..31128063e7a 100644 --- a/lib/index-gl2d.js +++ b/lib/index-gl2d.js @@ -18,4 +18,10 @@ Plotly.register([ require('./parcoords') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-gl3d.js b/lib/index-gl3d.js index 7134846cb7d..b7a635e27f9 100644 --- a/lib/index-gl3d.js +++ b/lib/index-gl3d.js @@ -16,4 +16,10 @@ Plotly.register([ require('./mesh3d') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index-mapbox.js b/lib/index-mapbox.js index 17b075b5f49..9c6ed2b4bf3 100644 --- a/lib/index-mapbox.js +++ b/lib/index-mapbox.js @@ -14,4 +14,10 @@ Plotly.register([ require('./scattermapbox') ]); +// locales +Plotly.register([ + require('./locale-en'), + require('./locale-en-us') +]); + module.exports = Plotly; diff --git a/lib/index.js b/lib/index.js index 7dac73a1f64..131ff4e8511 100644 --- a/lib/index.js +++ b/lib/index.js @@ -71,4 +71,10 @@ Plotly.register([ require('./calendars') ]); +// locales +Plotly.register([ + require('./locale-en.js'), + require('./locale-en-us.js') +]); + module.exports = Plotly; diff --git a/lib/locale-en-us.js b/lib/locale-en-us.js new file mode 100644 index 00000000000..97996970ae0 --- /dev/null +++ b/lib/locale-en-us.js @@ -0,0 +1,17 @@ +/** +* Copyright 2012-2017, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + moduleType: 'locale', + name: 'en-US', + dictionary: { + 'Click to enter Colorscale title': 'Click to enter Colorscale title' + } +}; diff --git a/lib/locale-en.js b/lib/locale-en.js new file mode 100644 index 00000000000..ead5a904c11 --- /dev/null +++ b/lib/locale-en.js @@ -0,0 +1,17 @@ +/** +* Copyright 2012-2017, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + moduleType: 'locale', + name: 'en', + dictionary: { + 'Click to enter Colorscale title': 'Click to enter Colourscale title' + } +}; diff --git a/package.json b/package.json index 1f15d00c564..788d6af96b7 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "bundle": "node tasks/bundle.js", "header": "node tasks/header.js", "stats": "node tasks/stats.js", - "build": "npm run preprocess && npm run bundle && npm run header && npm run stats", + "find-strings": "node tasks/find_locale_strings.js", + "build": "npm run preprocess && npm run find-strings && npm run bundle && npm run header && npm run stats", "cibuild": "npm run preprocess && node tasks/cibundle.js", "watch": "node tasks/watch.js", "lint": "eslint --version && eslint .", @@ -36,7 +37,7 @@ "test-image": "node tasks/test_image.js", "test-image-gl2d": "node tasks/test_image.js gl2d_* --queue", "test-export": "node tasks/test_export.js", - "test-syntax": "node tasks/test_syntax.js", + "test-syntax": "node tasks/test_syntax.js && npm run find-strings", "test-bundle": "node tasks/test_bundle.js", "test": "npm run test-jasmine && npm run test-bundle && npm run test-image && npm run test-image-gl2d && npm run test-syntax && npm run lint", "start-test_dashboard": "node devtools/test_dashboard/server.js", @@ -121,6 +122,7 @@ "glslify": "^4.0.0", "gzip-size": "^3.0.0", "image-size": "^0.5.1", + "into-stream": "^3.1.0", "jasmine-core": "^2.4.1", "jsdom": "^11.2.0", "karma": "^1.5.0", diff --git a/src/components/colorbar/attributes.js b/src/components/colorbar/attributes.js index aa2c456c9de..197bfa3553f 100644 --- a/src/components/colorbar/attributes.js +++ b/src/components/colorbar/attributes.js @@ -177,7 +177,6 @@ module.exports = overrideAll({ title: { valType: 'string', role: 'info', - dflt: 'Click to enter colorscale title', description: 'Sets the title of the color bar.' }, titlefont: fontAttrs({ diff --git a/src/components/colorbar/defaults.js b/src/components/colorbar/defaults.js index be767c67524..469a6528102 100644 --- a/src/components/colorbar/defaults.js +++ b/src/components/colorbar/defaults.js @@ -59,7 +59,7 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) { handleTickMarkDefaults(colorbarIn, colorbarOut, coerce, 'linear', {outerTicks: false, font: layout.font, noHover: true}); - coerce('title'); + coerce('title', layout._dfltTitle.colorbar); Lib.coerceFont(coerce, 'titlefont', layout.font); coerce('titleside'); }; diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index d584c134fa8..57f853006da 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -455,7 +455,7 @@ module.exports = function draw(gd, id) { propContainer: cbAxisOut, propName: propName, traceIndex: trace.index, - dfltName: 'colorscale', + placeholder: fullLayout._dfltTitle.colorbar, containerGroup: container.select('.cbtitle') }; diff --git a/src/components/legend/handle_click.js b/src/components/legend/handle_click.js index 46ce749f16f..933c63f388b 100644 --- a/src/components/legend/handle_click.js +++ b/src/components/legend/handle_click.js @@ -87,7 +87,7 @@ module.exports = function handleClick(g, gd, numClicks) { } if(numClicks === 1 && SHOWISOLATETIP && gd.data && gd._context.showTips) { - Lib.notifier('Double click on legend to isolate individual trace', 'long'); + Lib.notifier(Lib._(gd, 'Double-click on legend to isolate one trace'), 'long'); SHOWISOLATETIP = false; } else { SHOWISOLATETIP = false; diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 0008398bfdd..681516f5b86 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -17,6 +17,8 @@ var downloadImage = require('../../snapshot/download'); var Icons = require('../../../build/ploticon'); +var _ = Lib._; + var modeBarButtons = module.exports = {}; /** @@ -47,31 +49,31 @@ var modeBarButtons = module.exports = {}; modeBarButtons.toImage = { name: 'toImage', - title: 'Download plot as a png', + title: function(gd) { return _(gd, 'Download plot as a png'); }, icon: Icons.camera, click: function(gd) { var format = 'png'; - Lib.notifier('Taking snapshot - this may take a few seconds', 'long'); + Lib.notifier(_(gd, 'Taking snapshot - this may take a few seconds'), 'long'); if(Lib.isIE()) { - Lib.notifier('IE only supports svg. Changing format to svg.', 'long'); + Lib.notifier(_(gd, 'IE only supports svg. Changing format to svg.'), 'long'); format = 'svg'; } downloadImage(gd, {'format': format}) .then(function(filename) { - Lib.notifier('Snapshot succeeded - ' + filename, 'long'); + Lib.notifier(_(gd, 'Snapshot succeeded') + ' - ' + filename, 'long'); }) .catch(function() { - Lib.notifier('Sorry there was a problem downloading your snapshot!', 'long'); + Lib.notifier(_(gd, 'Sorry, there was a problem downloading your snapshot!'), 'long'); }); } }; modeBarButtons.sendDataToCloud = { name: 'sendDataToCloud', - title: 'Edit in Chart Studio', + title: function(gd) { return _(gd, 'Edit in Chart Studio'); }, icon: Icons.disk, click: function(gd) { Plots.sendDataToCloud(gd); @@ -80,7 +82,7 @@ modeBarButtons.sendDataToCloud = { modeBarButtons.zoom2d = { name: 'zoom2d', - title: 'Zoom', + title: function(gd) { return _(gd, 'Zoom'); }, attr: 'dragmode', val: 'zoom', icon: Icons.zoombox, @@ -89,7 +91,7 @@ modeBarButtons.zoom2d = { modeBarButtons.pan2d = { name: 'pan2d', - title: 'Pan', + title: function(gd) { return _(gd, 'Pan'); }, attr: 'dragmode', val: 'pan', icon: Icons.pan, @@ -98,7 +100,7 @@ modeBarButtons.pan2d = { modeBarButtons.select2d = { name: 'select2d', - title: 'Box Select', + title: function(gd) { return _(gd, 'Box Select'); }, attr: 'dragmode', val: 'select', icon: Icons.selectbox, @@ -107,7 +109,7 @@ modeBarButtons.select2d = { modeBarButtons.lasso2d = { name: 'lasso2d', - title: 'Lasso Select', + title: function(gd) { return _(gd, 'Lasso Select'); }, attr: 'dragmode', val: 'lasso', icon: Icons.lasso, @@ -116,7 +118,7 @@ modeBarButtons.lasso2d = { modeBarButtons.zoomIn2d = { name: 'zoomIn2d', - title: 'Zoom in', + title: function(gd) { return _(gd, 'Zoom in'); }, attr: 'zoom', val: 'in', icon: Icons.zoom_plus, @@ -125,7 +127,7 @@ modeBarButtons.zoomIn2d = { modeBarButtons.zoomOut2d = { name: 'zoomOut2d', - title: 'Zoom out', + title: function(gd) { return _(gd, 'Zoom out'); }, attr: 'zoom', val: 'out', icon: Icons.zoom_minus, @@ -134,7 +136,7 @@ modeBarButtons.zoomOut2d = { modeBarButtons.autoScale2d = { name: 'autoScale2d', - title: 'Autoscale', + title: function(gd) { return _(gd, 'Autoscale'); }, attr: 'zoom', val: 'auto', icon: Icons.autoscale, @@ -143,7 +145,7 @@ modeBarButtons.autoScale2d = { modeBarButtons.resetScale2d = { name: 'resetScale2d', - title: 'Reset axes', + title: function(gd) { return _(gd, 'Reset axes'); }, attr: 'zoom', val: 'reset', icon: Icons.home, @@ -152,7 +154,7 @@ modeBarButtons.resetScale2d = { modeBarButtons.hoverClosestCartesian = { name: 'hoverClosestCartesian', - title: 'Show closest data on hover', + title: function(gd) { return _(gd, 'Show closest data on hover'); }, attr: 'hovermode', val: 'closest', icon: Icons.tooltip_basic, @@ -162,7 +164,7 @@ modeBarButtons.hoverClosestCartesian = { modeBarButtons.hoverCompareCartesian = { name: 'hoverCompareCartesian', - title: 'Compare data on hover', + title: function(gd) { return _(gd, 'Compare data on hover'); }, attr: 'hovermode', val: function(gd) { return gd._fullLayout._isHoriz ? 'y' : 'x'; @@ -256,7 +258,7 @@ function handleCartesian(gd, ev) { modeBarButtons.zoom3d = { name: 'zoom3d', - title: 'Zoom', + title: function(gd) { return _(gd, 'Zoom'); }, attr: 'scene.dragmode', val: 'zoom', icon: Icons.zoombox, @@ -265,7 +267,7 @@ modeBarButtons.zoom3d = { modeBarButtons.pan3d = { name: 'pan3d', - title: 'Pan', + title: function(gd) { return _(gd, 'Pan'); }, attr: 'scene.dragmode', val: 'pan', icon: Icons.pan, @@ -274,7 +276,7 @@ modeBarButtons.pan3d = { modeBarButtons.orbitRotation = { name: 'orbitRotation', - title: 'orbital rotation', + title: function(gd) { return _(gd, 'Orbital rotation'); }, attr: 'scene.dragmode', val: 'orbit', icon: Icons['3d_rotate'], @@ -283,7 +285,7 @@ modeBarButtons.orbitRotation = { modeBarButtons.tableRotation = { name: 'tableRotation', - title: 'turntable rotation', + title: function(gd) { return _(gd, 'Turntable rotation'); }, attr: 'scene.dragmode', val: 'turntable', icon: Icons['z-axis'], @@ -309,7 +311,7 @@ function handleDrag3d(gd, ev) { modeBarButtons.resetCameraDefault3d = { name: 'resetCameraDefault3d', - title: 'Reset camera to default', + title: function(gd) { return _(gd, 'Reset camera to default'); }, attr: 'resetDefault', icon: Icons.home, click: handleCamera3d @@ -317,7 +319,7 @@ modeBarButtons.resetCameraDefault3d = { modeBarButtons.resetCameraLastSave3d = { name: 'resetCameraLastSave3d', - title: 'Reset camera to last save', + title: function(gd) { return _(gd, 'Reset camera to last save'); }, attr: 'resetLastSave', icon: Icons.movie, click: handleCamera3d @@ -348,7 +350,7 @@ function handleCamera3d(gd, ev) { modeBarButtons.hoverClosest3d = { name: 'hoverClosest3d', - title: 'Toggle show closest data on hover', + title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, toggle: true, @@ -409,7 +411,7 @@ function handleHover3d(gd, ev) { modeBarButtons.zoomInGeo = { name: 'zoomInGeo', - title: 'Zoom in', + title: function(gd) { return _(gd, 'Zoom in'); }, attr: 'zoom', val: 'in', icon: Icons.zoom_plus, @@ -418,7 +420,7 @@ modeBarButtons.zoomInGeo = { modeBarButtons.zoomOutGeo = { name: 'zoomOutGeo', - title: 'Zoom out', + title: function(gd) { return _(gd, 'Zoom out'); }, attr: 'zoom', val: 'out', icon: Icons.zoom_minus, @@ -427,7 +429,7 @@ modeBarButtons.zoomOutGeo = { modeBarButtons.resetGeo = { name: 'resetGeo', - title: 'Reset', + title: function(gd) { return _(gd, 'Reset'); }, attr: 'reset', val: null, icon: Icons.autoscale, @@ -436,7 +438,7 @@ modeBarButtons.resetGeo = { modeBarButtons.hoverClosestGeo = { name: 'hoverClosestGeo', - title: 'Toggle show closest data on hover', + title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, toggle: true, @@ -469,7 +471,7 @@ function handleGeo(gd, ev) { modeBarButtons.hoverClosestGl2d = { name: 'hoverClosestGl2d', - title: 'Toggle show closest data on hover', + title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, toggle: true, @@ -480,7 +482,7 @@ modeBarButtons.hoverClosestGl2d = { modeBarButtons.hoverClosestPie = { name: 'hoverClosestPie', - title: 'Toggle show closest data on hover', + title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: 'closest', icon: Icons.tooltip_basic, @@ -506,7 +508,7 @@ function toggleHover(gd) { modeBarButtons.toggleHover = { name: 'toggleHover', - title: 'Toggle show closest data on hover', + title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, toggle: true, @@ -524,7 +526,7 @@ modeBarButtons.toggleHover = { modeBarButtons.resetViews = { name: 'resetViews', - title: 'Reset views', + title: function(gd) { return _(gd, 'Reset views'); }, icon: Icons.home, click: function(gd, ev) { var button = ev.currentTarget; @@ -543,7 +545,7 @@ modeBarButtons.resetViews = { modeBarButtons.toggleSpikelines = { name: 'toggleSpikelines', - title: 'Toggle Spike Lines', + title: function(gd) { return _(gd, 'Toggle Spike Lines'); }, icon: Icons.spikeline, attr: '_cartesianSpikesEnabled', val: 'on', @@ -578,7 +580,7 @@ function setSpikelineVisibility(gd) { modeBarButtons.resetViewMapbox = { name: 'resetViewMapbox', - title: 'Reset view', + title: function(gd) { return _(gd, 'Reset view'); }, attr: 'reset', icon: Icons.home, click: function(gd) { diff --git a/src/components/modebar/modebar.js b/src/components/modebar/modebar.js index 5e87b2413a8..9f0ae02f64d 100644 --- a/src/components/modebar/modebar.js +++ b/src/components/modebar/modebar.js @@ -123,6 +123,9 @@ proto.createButton = function(config) { var title = config.title; if(title === undefined) title = config.name; + // for localization: allow title to be a callable that takes gd as arg + else if(typeof title === 'function') title = title(this.graphInfo); + if(title || title === 0) button.setAttribute('data-title', title); if(config.attr !== undefined) button.setAttribute('data-attr', config.attr); @@ -250,7 +253,7 @@ proto.getLogo = function() { a.href = 'https://plot.ly/'; a.target = '_blank'; - a.setAttribute('data-title', 'Produced with Plotly'); + a.setAttribute('data-title', Lib._(this.graphInfo, 'Produced with Plotly')); a.className = 'modebar-btn plotlyjsicon modebar-btn--logo'; a.appendChild(this.createIcon(Icons.plotlylogo)); diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 0e68681356b..54d41e84952 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -372,7 +372,8 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) { width: opts._width, height: opts._height, margin: { t: 0, b: 0, l: 0, r: 0 } - } + }, + _context: gd._context }; mockFigure.layout[oppAxisName] = { diff --git a/src/components/titles/index.js b/src/components/titles/index.js index a2819784c7b..ad7a6eb17b0 100644 --- a/src/components/titles/index.js +++ b/src/components/titles/index.js @@ -20,10 +20,10 @@ var Color = require('../color'); var svgTextUtils = require('../../lib/svg_text_utils'); var interactConstants = require('../../constants/interactions'); -var PLACEHOLDER_RE = /Click to enter .+ title/; - var Titles = module.exports = {}; +var numStripRE = / [XY][0-9]* /; + /** * Titles - (re)draw titles on the axes and plot: * @param {DOM element} gd - the graphDiv @@ -35,7 +35,7 @@ var Titles = module.exports = {}; * [traceIndex] - include only if this property applies to one trace * (such as a colorbar title) - then editing pipes to Plotly.restyle * instead of Plotly.relayout - * dfltName - the name of the title in placeholder text + * placeholder - placeholder text for an empty editable title * [avoid] {object} - include if this title should move to avoid other elements * selection - d3 selection of elements to avoid * side - which direction to move if there is a conflict @@ -55,8 +55,8 @@ var Titles = module.exports = {}; Titles.draw = function(gd, titleClass, options) { var cont = options.propContainer; var prop = options.propName; + var placeholder = options.placeholder; var traceIndex = options.traceIndex; - var name = options.dfltName; var avoid = options.avoid || {}; var attributes = options.attributes; var transform = options.transform; @@ -80,7 +80,11 @@ Titles.draw = function(gd, titleClass, options) { var editable = gd._context.edits[editAttr]; if(txt === '') opacity = 0; - if(txt.match(PLACEHOLDER_RE)) { + // look for placeholder text while stripping out numbers from eg X2, Y3 + // this is just for backward compatibility with the old version that had + // "Click to enter X2 title" and may have gotten saved in some old plots, + // we don't want this to show up when these are displayed. + else if(txt.replace(numStripRE, ' % ') === placeholder.replace(numStripRE, ' % ')) { opacity = 0.2; isplaceholder = true; if(!editable) txt = ''; @@ -199,13 +203,10 @@ Titles.draw = function(gd, titleClass, options) { el.call(titleLayout); - var placeholderText = 'Click to enter ' + name + ' title'; - function setPlaceholder() { opacity = 0; isplaceholder = true; - txt = placeholderText; - el.text(txt) + el.text(placeholder) .on('mouseover.opacity', function() { d3.select(this).transition() .duration(interactConstants.SHOW_PLACEHOLDER).style('opacity', 1); diff --git a/src/lib/dates.js b/src/lib/dates.js index c5c05fcfda9..7b959c1c2c4 100644 --- a/src/lib/dates.js +++ b/src/lib/dates.js @@ -12,7 +12,7 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); -var logError = require('./loggers').error; +var Loggers = require('./loggers'); var mod = require('./mod'); var constants = require('../constants/numerical'); @@ -340,7 +340,7 @@ exports.cleanDate = function(v, dflt, calendar) { // do not allow milliseconds (old) or jsdate objects (inherently // described as gregorian dates) with world calendars if(isWorldCalendar(calendar)) { - logError('JS Dates and milliseconds are incompatible with world calendars', v); + Loggers.error('JS Dates and milliseconds are incompatible with world calendars', v); return dflt; } @@ -351,7 +351,7 @@ exports.cleanDate = function(v, dflt, calendar) { if(!v && dflt !== undefined) return dflt; } else if(!exports.isDateTime(v, calendar)) { - logError('unrecognized date', v); + Loggers.error('unrecognized date', v); return dflt; } return v; @@ -551,7 +551,7 @@ exports.incrementMonth = function(ms, dMonth, calendar) { return (cDate.toJD() - EPOCHJD) * ONEDAY + timeMs; } catch(e) { - logError('invalid ms ' + ms + ' in calendar ' + calendar); + Loggers.error('invalid ms ' + ms + ' in calendar ' + calendar); // then keep going in gregorian even though the result will be 'Invalid' } } diff --git a/src/lib/geo_location_utils.js b/src/lib/geo_location_utils.js index 9d1620e13c9..3879355f104 100644 --- a/src/lib/geo_location_utils.js +++ b/src/lib/geo_location_utils.js @@ -34,7 +34,7 @@ exports.locationToFeature = function(locationmode, location, features) { if(feature.id === locationId) return feature; } - Lib.warn([ + Lib.log([ 'Location with id', locationId, 'does not have a matching topojson feature at this resolution.' ].join(' ')); @@ -56,7 +56,7 @@ function countryNameToISO3(countryName) { if(regex.test(countryName.trim().toLowerCase())) return iso3; } - Lib.warn('Unrecognized country name: ' + countryName + '.'); + Lib.log('Unrecognized country name: ' + countryName + '.'); return false; } diff --git a/src/lib/index.js b/src/lib/index.js index 2912bfdb642..88c7cc495c9 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -106,6 +106,8 @@ lib.clearThrottle = throttleModule.clear; lib.getGraphDiv = require('./get_graph_div'); +lib._ = require('./localize'); + lib.notifier = require('./notifier'); lib.filterUnique = require('./filter_unique'); diff --git a/src/lib/localize.js b/src/lib/localize.js new file mode 100644 index 00000000000..4a5e367c12c --- /dev/null +++ b/src/lib/localize.js @@ -0,0 +1,54 @@ +/** +* Copyright 2012-2017, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var Registry = require('../registry'); + +/** + * localize: translate a string for the current locale + * + * @param {object} gd: the graphDiv for context + * gd._context.locale determines the language (& optional region/country) + * the dictionary for each locale may either be supplied in + * gd._context.dictionaries or globally via Plotly.register + * @param {string} s: the string to translate + */ +module.exports = function localize(gd, s) { + var locale = gd._context.locale; + + /* + * Priority of lookup: + * contextDicts[locale], + * registeredDicts[locale], + * contextDicts[baseLocale], (if baseLocale is distinct) + * registeredDicts[baseLocale] + * Return the first translation we find. + * This way if you have a regionalization you are allowed to specify + * only what's different from the base locale, everything else will + * fall back on the base. + */ + for(var i = 0; i < 2; i++) { + var dicts = gd._context.dictionaries; + for(var j = 0; j < 2; j++) { + var dict = dicts[locale]; + if(dict) { + var out = dict[s]; + if(out) return out; + } + dicts = Registry.localeRegistry; + } + + var baseLocale = locale.split('-')[0]; + if(baseLocale === locale) break; + locale = baseLocale; + } + + return s; +}; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 205994bf1a6..22016271911 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -565,7 +565,6 @@ function plotPolar(gd, data, layout) { var opacity = 1; var txt = gd._fullLayout.title; if(txt === '' || !txt) opacity = 0; - var placeholderText = 'Click to enter title'; var titleLayout = function() { this.call(svgTextUtils.convertToTspans, gd); @@ -577,6 +576,7 @@ function plotPolar(gd, data, layout) { .call(titleLayout); if(gd._context.edits.titleText) { + var placeholderText = Lib._(gd, 'Click to enter Plot title'); if(!txt || txt === placeholderText) { opacity = 0.2; // placeholder is not going through convertToTspans diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 27f4735a24e..b1663e6b9ac 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -122,9 +122,26 @@ module.exports = { // Turn all console logging on or off (errors will be thrown) // This should ONLY be set via Plotly.setPlotConfig - logging: false, + // 0: no logs + // 1: warnings and errors, but not informational messages + // 2: verbose logs + logging: 1, // Set global transform to be applied to all traces with no // specification needed - globalTransforms: [] + globalTransforms: [], + + // Which localization should we use? + // Should be a string like 'en' or 'en-US'. + locale: 'en-US', + + // Localization dictionaries + // Dictionaries can be provided either here (specific to one chart) or globally + // by registering them as modules. + // Here `dictionaries` should be an object of objects + // {'da': {'Reset axes': 'Nulstil aksler', ...}, ...} + // When looking for a translation we look at these dictionaries first, then + // the ones registered as modules. If those fail, we strip off any + // regionalization ('en-US' -> 'en') and try each again + dictionaries: {} }; diff --git a/src/plot_api/register.js b/src/plot_api/register.js index 359cfb08bfe..bc6a3141be3 100644 --- a/src/plot_api/register.js +++ b/src/plot_api/register.js @@ -40,6 +40,10 @@ module.exports = function register(_modules) { registerComponentModule(newModule); break; + case 'locale': + Registry.registerLocale(newModule); + break; + default: throw new Error('Invalid module was attempted to be registered!'); } diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index f59434c9963..78fae75a679 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -414,7 +414,7 @@ exports.drawMainTitle = function(gd) { Titles.draw(gd, 'gtitle', { propContainer: fullLayout, propName: 'title', - dfltName: 'Plot', + placeholder: fullLayout._dfltTitle.plot, attributes: { x: fullLayout.width / 2, y: fullLayout._size.t / 2, diff --git a/src/plot_api/validate.js b/src/plot_api/validate.js index 95ae68780f2..76c1d11bc7c 100644 --- a/src/plot_api/validate.js +++ b/src/plot_api/validate.js @@ -13,6 +13,7 @@ var Lib = require('../lib'); var Plots = require('../plots/plots'); var PlotSchema = require('./plot_schema'); +var dfltConfig = require('./plot_config'); var isPlainObject = Lib.isPlainObject; var isArray = Array.isArray; @@ -40,9 +41,9 @@ var isArray = Array.isArray; * error message (shown in console in logger config argument is enable) */ module.exports = function valiate(data, layout) { - var schema = PlotSchema.get(), - errorList = [], - gd = {}; + var schema = PlotSchema.get(); + var errorList = []; + var gd = {_context: Lib.extendFlat({}, dfltConfig)}; var dataIn, layoutIn; diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 3b24d00cc41..a72ed431335 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2255,7 +2255,7 @@ axes.doTicks = function(gd, axid, skipTitle) { Titles.draw(gd, axid + 'title', { propContainer: ax, propName: ax._name + '.title', - dfltName: axLetter.toUpperCase() + ' axis', + placeholder: fullLayout._dfltTitle[axLetter], avoid: avoid, transform: transform, attributes: {x: x, y: y, 'text-anchor': 'middle'} @@ -2481,7 +2481,7 @@ function swapAxisGroup(gd, xIds, yIds) { if(allEqual) { if(coerceLinearX) layout[xFullAxes[0]._name].type = 'linear'; if(coerceLinearY) layout[yFullAxes[0]._name].type = 'linear'; - swapAxisAttrs(layout, keyi, xFullAxes, yFullAxes); + swapAxisAttrs(layout, keyi, xFullAxes, yFullAxes, gd._fullLayout._dfltTitle); } } @@ -2495,7 +2495,7 @@ function swapAxisGroup(gd, xIds, yIds) { } } -function swapAxisAttrs(layout, key, xFullAxes, yFullAxes) { +function swapAxisAttrs(layout, key, xFullAxes, yFullAxes, dfltTitle) { // in case the value is the default for either axis, // look at the first axis in each list and see if // this key's value is undefined @@ -2505,11 +2505,11 @@ function swapAxisAttrs(layout, key, xFullAxes, yFullAxes) { i; if(key === 'title') { // special handling of placeholder titles - if(xVal === 'Click to enter X axis title') { - xVal = 'Click to enter Y axis title'; + if(xVal === dfltTitle.x) { + xVal = dfltTitle.y; } - if(yVal === 'Click to enter Y axis title') { - yVal = 'Click to enter X axis title'; + if(yVal === dfltTitle.y) { + yVal = dfltTitle.x; } } diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 631255c5a9f..469c5c677c1 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -37,11 +37,8 @@ var orderedCategories = require('./ordered_categories'); * bgColor: the plot background color, to calculate default gridline colors */ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) { - var letter = options.letter, - font = options.font || {}, - defaultTitle = 'Click to enter ' + - (options.title || (letter.toUpperCase() + ' axis')) + - ' title'; + var letter = options.letter; + var font = options.font || {}; function coerce2(attr, dflt) { return Lib.coerce2(containerIn, containerOut, layoutAttributes, attr, dflt); @@ -77,7 +74,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, // inherit from global font color in case that was provided. var dfltFontColor = (dfltColor === containerIn.color) ? dfltColor : font.color; - coerce('title', defaultTitle); + coerce('title', layoutOut._dfltTitle[letter]); Lib.coerceFont(coerce, 'titlefont', { family: font.family, size: Math.round(font.size * 1.2), diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index 1b7ca54a061..ec01349e05d 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -296,7 +296,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) { dragTail(zoomMode); if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) { - Lib.notifier('Double-click to
zoom back out', 'long'); + Lib.notifier(Lib._(gd, 'Double-click to zoom back out'), 'long'); SHOWZOOMOUTTIP = false; } } diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 08691f1879b..a1ea55c76fd 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -381,11 +381,8 @@ module.exports = function setConvert(ax, fullLayout) { } if(!isFinite(ax._m) || !isFinite(ax._b)) { - Lib.notifier( - 'Something went wrong with axis scaling', - 'long'); fullLayout._replotting = false; - throw new Error('axis scaling'); + throw new Error('Something went wrong with axis scaling'); } }; diff --git a/src/plots/command.js b/src/plots/command.js index 8799ee07fad..a0657084c9b 100644 --- a/src/plots/command.js +++ b/src/plots/command.js @@ -114,7 +114,7 @@ exports.manageCommandObserver = function(gd, container, commandList, onchange) { } else { // TODO: It'd be really neat to actually give a *reason* for this, but at least a warning // is a start - Lib.warn('Unable to automatically bind plot updates to API command'); + Lib.log('Unable to automatically bind plot updates to API command'); ret.lookupTable = {}; ret.remove = function() {}; diff --git a/src/plots/gl2d/convert.js b/src/plots/gl2d/convert.js index 78784294fe9..fd50b3a787d 100644 --- a/src/plots/gl2d/convert.js +++ b/src/plots/gl2d/convert.js @@ -109,12 +109,13 @@ proto.merge = function(options) { for(i = 0; i < 2; ++i) { axisName = AXES[i]; + var axisLetter = axisName.charAt(0); // get options relevant to this subplot, // '_name' is e.g. xaxis, xaxis2, yaxis, yaxis4 ... ax = options[this.scene[axisName]._name]; - axTitle = /Click to enter .+ title/.test(ax.title) ? '' : ax.title; + axTitle = ax.title === this.scene.fullLayout._dfltTitle[axisLetter] ? '' : ax.title; for(j = 0; j <= 2; j += 2) { this.labelEnable[i + j] = false; diff --git a/src/plots/gl3d/layout/axis_defaults.js b/src/plots/gl3d/layout/axis_defaults.js index d65756b1e06..0df2e8db8b7 100644 --- a/src/plots/gl3d/layout/axis_defaults.js +++ b/src/plots/gl3d/layout/axis_defaults.js @@ -44,14 +44,16 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) { handleAxisDefaults( containerIn, containerOut, - coerce, { + coerce, + { font: options.font, letter: axName[0], data: options.data, showGrid: true, bgColor: options.bgColor, calendar: options.calendar - }); + }, + options.fullLayout); coerce('gridcolor', colorMix(containerOut.color, options.bgColor, gridLightness).toRgbString()); coerce('title', axName[0]); // shouldn't this be on-par with 2D? diff --git a/src/plots/gl3d/layout/defaults.js b/src/plots/gl3d/layout/defaults.js index 04d4f841a8c..56062cc392d 100644 --- a/src/plots/gl3d/layout/defaults.js +++ b/src/plots/gl3d/layout/defaults.js @@ -102,7 +102,8 @@ function handleGl3dDefaults(sceneLayoutIn, sceneLayoutOut, coerce, opts) { scene: opts.id, data: opts.fullData, bgColor: bgColorCombined, - calendar: opts.calendar + calendar: opts.calendar, + fullLayout: opts.fullLayout }); Registry.getComponentMethod('annotations3d', 'handleDefaults')( diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 7c23ffd77e8..86f473a6afb 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -28,7 +28,6 @@ module.exports = { title: { valType: 'string', role: 'info', - dflt: 'Click to enter Plot title', editType: 'layoutstyle', description: [ 'Sets the plot\'s title.' diff --git a/src/plots/plots.js b/src/plots/plots.js index 5d0515a0a42..db5d224674a 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -16,6 +16,7 @@ var Plotly = require('../plotly'); var PlotSchema = require('../plot_api/plot_schema'); var Registry = require('../registry'); var Lib = require('../lib'); +var _ = Lib._; var Color = require('../components/color'); var BADNUM = require('../constants/numerical').BADNUM; @@ -418,6 +419,25 @@ plots.supplyDefaults = function(gd) { // Create all the storage space for frames, but only if doesn't already exist if(!gd._transitionData) plots.createTransitionData(gd); + // So we only need to do this once (and since we have gd here) + // get the translated placeholder titles. + // These ones get used as default values so need to be known at supplyDefaults + // others keep their blank defaults but render the placeholder as desired later + // TODO: make these work the same way, only inserting the placeholder text at draw time? + // The challenge is that this has slightly different behavior right now in editable mode: + // using the placeholder as default makes this text permanently (but lightly) visible, + // but explicit '' for these titles gives you a placeholder that's hidden until you mouse + // over it - so you're not distracted by it if you really don't want a title, but if you do + // and you're new to plotly you may not be able to find it. + // When editable=false the two behave the same, no title is drawn. + newFullLayout._dfltTitle = { + plot: _(gd, 'Click to enter Plot title'), + x: _(gd, 'Click to enter X axis title'), + y: _(gd, 'Click to enter Y axis title'), + colorbar: _(gd, 'Click to enter Colorscale title') + }; + newFullLayout._traceWord = _(gd, 'trace'); + // first fill in what we can of layout without looking at data // because fullData needs a few things from layout @@ -586,8 +606,8 @@ plots._hasPlotType = function(category) { var modules = this._modules || []; for(i = 0; i < modules.length; i++) { - var _ = modules[i]; - if(_.categories && _.categories.indexOf(category) >= 0) { + var modulei = modules[i]; + if(modulei.categories && modulei.categories.indexOf(category) >= 0) { return true; } } @@ -992,7 +1012,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOutIndex, layout, traceInInde coerce('type'); coerce('uid'); - coerce('name', 'trace ' + traceInIndex); + coerce('name', layout._traceWord + ' ' + traceInIndex); // coerce subplot attributes of all registered subplot types var subplotTypes = Object.keys(subplotsRegistry); @@ -1131,7 +1151,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) { var globalFont = Lib.coerceFont(coerce, 'font'); - coerce('title'); + coerce('title', layoutOut._dfltTitle.plot); Lib.coerceFont(coerce, 'titlefont', { family: globalFont.family, diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 6549fe03fa2..1240c653c60 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -14,6 +14,7 @@ var tinycolor = require('tinycolor2'); var Plotly = require('../../plotly'); var Lib = require('../../lib'); +var _ = Lib._; var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var setConvert = require('../cartesian/set_convert'); @@ -382,7 +383,7 @@ proto.drawAxes = function(doTitles) { Titles.draw(gd, 'a' + titlesuffix, { propContainer: aaxis, propName: _this.id + '.aaxis.title', - dfltName: 'Component A', + placeholder: _(gd, 'Click to enter Component A title'), attributes: { x: _this.x0 + _this.w / 2, y: _this.y0 - aaxis.titlefont.size / 3 - apad, @@ -396,7 +397,7 @@ proto.drawAxes = function(doTitles) { Titles.draw(gd, 'b' + titlesuffix, { propContainer: baxis, propName: _this.id + '.baxis.title', - dfltName: 'Component B', + placeholder: _(gd, 'Click to enter Component B title'), attributes: { x: _this.x0 - bpad, y: _this.y0 + _this.h + baxis.titlefont.size * 0.83 + bpad, @@ -407,7 +408,7 @@ proto.drawAxes = function(doTitles) { Titles.draw(gd, 'c' + titlesuffix, { propContainer: caxis, propName: _this.id + '.caxis.title', - dfltName: 'Component C', + placeholder: _(gd, 'Click to enter Component C title'), attributes: { x: _this.x0 + _this.w + bpad, y: _this.y0 + _this.h + caxis.titlefont.size * 0.83 + bpad, @@ -588,7 +589,7 @@ proto.initInteractions = function() { Plotly.relayout(gd, attrs); if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) { - Lib.notifier('Double-click to
zoom back out', 'long'); + Lib.notifier(_(gd, 'Double-click to zoom back out'), 'long'); SHOWZOOMOUTTIP = false; } } diff --git a/src/registry.js b/src/registry.js index 70b6a2015c6..b688c1df2dd 100644 --- a/src/registry.js +++ b/src/registry.js @@ -28,6 +28,7 @@ exports.componentsRegistry = {}; exports.layoutArrayContainers = []; exports.layoutArrayRegexes = []; exports.traceLayoutAttributes = {}; +exports.localeRegistry = {}; /** * register a module as the handler for a trace type @@ -311,3 +312,39 @@ function getTraceType(traceType) { if(typeof traceType === 'object') traceType = traceType.type; return traceType; } + +/** + * Register a new locale dictionary + * + * @param {object} module + * @param {string} moduleType + * should be 'locale' so that Plotly.register will forward to this function + * @param {string} module.name + * the locale name. Should be a 2-digit language string ('en', 'de') + * optionally with a country/region code ('en-GB', 'de-CH'). If a country + * code is used but the base language locale has not yet been supplied, + * we will use this locale for the base as well. + * @param {object} module.dictionary + * the dictionary mapping input strings to localized strings + * generally the keys should be the literal input strings, but + * if default translations are provided you can use any string as a key. + */ +exports.registerLocale = function(_module) { + var locale = _module.name; + var baseLocale = locale.split('-')[0]; + + var newDict = _module.dictionary; + + var locales = exports.localeRegistry; + + // Should we use this dict for the base locale? + // In case we're overwriting a previous dict for this locale, check + // whether the base matches the full locale dict now. If we're not + // overwriting, locales[locale] is undefined so this just checks if + // baseLocale already had a dict or not. + if(baseLocale !== locale && locales[baseLocale] === locales[locale]) { + locales[baseLocale] = newDict; + } + + locales[locale] = newDict; +}; diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js index f085eb9306b..b6a5fa83139 100644 --- a/src/traces/box/calc.js +++ b/src/traces/box/calc.js @@ -11,6 +11,7 @@ var isNumeric = require('fast-isnumeric'); var Lib = require('../../lib'); +var _ = Lib._; var Axes = require('../../plots/cartesian/axes'); // outlier definition based on http://www.physics.csbsju.edu/stats/box2.html @@ -122,7 +123,17 @@ module.exports = function calc(gd, trace) { num: fullLayout[numKey], dPos: dPos, posLetter: posLetter, - valLetter: valLetter + valLetter: valLetter, + labels: { + med: _(gd, 'median:'), + min: _(gd, 'min:'), + q1: _(gd, 'q1:'), + q3: _(gd, 'q3:'), + max: _(gd, 'max:'), + mean: trace.boxmean === 'sd' ? _(gd, 'mean ± σ:') : _(gd, 'mean:'), + lf: _(gd, 'lower fence:'), + uf: _(gd, 'upper fence:') + } }; fullLayout[numKey]++; diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 17cc4c1f84c..839f065e72e 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -138,15 +138,12 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { // box plots: each "point" gets many labels var usedVals = {}; var attrs = ['med', 'min', 'q1', 'q3', 'max']; - var prefixes = ['median', 'min', 'q1', 'q3', 'max']; if(trace.boxmean || (trace.meanline || {}).visible) { attrs.push('mean'); - prefixes.push(trace.boxmean === 'sd' ? 'mean ± σ' : 'mean'); } if(trace.boxpoints || trace.points) { attrs.push('lf', 'uf'); - prefixes.push('lower fence', 'upper fence'); } for(var i = 0; i < attrs.length; i++) { @@ -162,7 +159,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx; pointData2[vLetter + 'LabelVal'] = val; - pointData2[vLetter + 'Label'] = prefixes[i] + ': ' + Axes.hoverLabelText(vAxis, val); + pointData2[vLetter + 'Label'] = t.labels[attr] + ' ' + Axes.hoverLabelText(vAxis, val); if(attr === 'mean' && ('sd' in di) && trace.boxmean === 'sd') { pointData2[vLetter + 'err'] = di.sd; diff --git a/src/traces/contourcarpet/calc.js b/src/traces/contourcarpet/calc.js index e313bbdbaf4..3691800dbd8 100644 --- a/src/traces/contourcarpet/calc.js +++ b/src/traces/contourcarpet/calc.js @@ -8,10 +8,8 @@ 'use strict'; -var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); var extendFlat = require('../../lib').extendFlat; -var Registry = require('../../registry'); var colorscaleCalc = require('../../components/colorscale/calc'); var hasColumns = require('../heatmap/has_columns'); var convertColumnData = require('../heatmap/convert_column_xyz'); @@ -126,18 +124,15 @@ function heatmappishCalc(gd, trace) { // prepare the raw data // run makeCalcdata on x and y even for heatmaps, in case of category mappings var carpet = trace.carpetTrace; - var aax = carpet.aaxis, - bax = carpet.baxis, - isContour = Registry.traceIs(trace, 'contour'), - zsmooth = isContour ? 'best' : trace.zsmooth, - a, + var aax = carpet.aaxis; + var bax = carpet.baxis; + var a, a0, da, b, b0, db, - z, - i; + z; // cancel minimum tick spacings (only applies to bars and boxes) aax._minDtick = 0; @@ -157,40 +152,6 @@ function heatmappishCalc(gd, trace) { trace._emptypoints = findEmpties(z); trace._interpz = interp2d(z, trace._emptypoints, trace._interpz); - function noZsmooth(msg) { - zsmooth = trace._input.zsmooth = trace.zsmooth = false; - Lib.notifier('cannot fast-zsmooth: ' + msg); - } - - // check whether we really can smooth (ie all boxes are about the same size) - if(zsmooth === 'fast') { - if(aax.type === 'log' || bax.type === 'log') { - noZsmooth('log axis found'); - } - else { - if(a.length) { - var avgda = (a[a.length - 1] - a[0]) / (a.length - 1), - maxErrX = Math.abs(avgda / 100); - for(i = 0; i < a.length - 1; i++) { - if(Math.abs(a[i + 1] - a[i] - avgda) > maxErrX) { - noZsmooth('a scale is not linear'); - break; - } - } - } - if(b.length && zsmooth === 'fast') { - var avgdy = (b[b.length - 1] - b[0]) / (b.length - 1), - maxErrY = Math.abs(avgdy / 100); - for(i = 0; i < b.length - 1; i++) { - if(Math.abs(b[i + 1] - b[i] - avgdy) > maxErrY) { - noZsmooth('b scale is not linear'); - break; - } - } - } - } - } - // create arrays of brick boundaries, to be used by autorange and heatmap.plot var xlen = maxRowLength(z), xIn = trace.xtype === 'scaled' ? '' : a, diff --git a/src/traces/heatmap/calc.js b/src/traces/heatmap/calc.js index b8ce599d5ed..802345d7dca 100644 --- a/src/traces/heatmap/calc.js +++ b/src/traces/heatmap/calc.js @@ -82,7 +82,7 @@ module.exports = function calc(gd, trace) { function noZsmooth(msg) { zsmooth = trace._input.zsmooth = trace.zsmooth = false; - Lib.notifier('cannot fast-zsmooth: ' + msg); + Lib.warn('cannot use zsmooth: "fast": ' + msg); } // check whether we really can smooth (ie all boxes are about the same size) diff --git a/src/traces/ohlc/transform.js b/src/traces/ohlc/transform.js index 8e952144afc..db357e012c7 100644 --- a/src/traces/ohlc/transform.js +++ b/src/traces/ohlc/transform.js @@ -12,6 +12,7 @@ var isNumeric = require('fast-isnumeric'); var Lib = require('../../lib'); +var _ = Lib._; var helpers = require('./helpers'); var Axes = require('../../plots/cartesian/axes'); var axisIds = require('../../plots/cartesian/axis_ids'); @@ -132,6 +133,11 @@ exports.calcTransform = function calcTransform(gd, trace, opts) { close = trace.close, textIn = trace.text; + var openName = _(gd, 'open:') + ' '; + var highName = _(gd, 'high:') + ' '; + var lowName = _(gd, 'low:') + ' '; + var closeName = _(gd, 'close:') + ' '; + var len = open.length, x = [], y = [], @@ -183,10 +189,10 @@ exports.calcTransform = function calcTransform(gd, trace, opts) { var t = []; if(hasY) { - t.push('Open: ' + format(ya, o)); - t.push('High: ' + format(ya, h)); - t.push('Low: ' + format(ya, l)); - t.push('Close: ' + format(ya, c)); + t.push(openName + format(ya, o)); + t.push(highName + format(ya, h)); + t.push(lowName + format(ya, l)); + t.push(closeName + format(ya, c)); } if(hasText) t.push(getTextItem(i)); diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js index 59d978fa4a4..6c4b37b4be4 100644 --- a/src/traces/sankey/plot.js +++ b/src/traces/sankey/plot.js @@ -15,6 +15,8 @@ var Color = require('../../components/color'); var Lib = require('../../lib'); var cn = require('./constants').cn; +var _ = Lib._; + function renderableValuePresent(d) {return d !== '';} function ownTrace(selection, d) { @@ -135,6 +137,11 @@ module.exports = function plot(gd, calcData) { }); }; + var sourceLabel = _(gd, 'source:') + ' '; + var targetLabel = _(gd, 'target:') + ' '; + var incomingLabel = _(gd, 'incoming flow count:') + ' '; + var outgoingLabel = _(gd, 'outgoing flow count:') + ' '; + var linkHoverFollow = function(element, d) { var trace = d.link.trace; var rootBBox = gd._fullLayout._paperdiv.node().getBoundingClientRect(); @@ -148,8 +155,8 @@ module.exports = function plot(gd, calcData) { name: d3.format(d.valueFormat)(d.link.value) + d.valueSuffix, text: [ d.link.label || '', - ['Source:', d.link.source.label].join(' '), - ['Target:', d.link.target.label].join(' ') + sourceLabel + d.link.source.label, + targetLabel + d.link.target.label ].filter(renderableValuePresent).join('
'), color: castHoverOption(trace, 'bgcolor') || Color.addOpacity(d.tinyColorHue, 1), borderColor: castHoverOption(trace, 'bordercolor'), @@ -209,8 +216,8 @@ module.exports = function plot(gd, calcData) { name: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix, text: [ d.node.label, - ['Incoming flow count:', d.node.targetLinks.length].join(' '), - ['Outgoing flow count:', d.node.sourceLinks.length].join(' ') + incomingLabel + d.node.targetLinks.length, + outgoingLabel + d.node.sourceLinks.length ].filter(renderableValuePresent).join('
'), color: castHoverOption(trace, 'bgcolor') || d.tinyColorHue, borderColor: castHoverOption(trace, 'bordercolor'), diff --git a/src/traces/scattergeo/calc.js b/src/traces/scattergeo/calc.js index 668e4e24aed..1ec011c4dde 100644 --- a/src/traces/scattergeo/calc.js +++ b/src/traces/scattergeo/calc.js @@ -16,6 +16,8 @@ var calcMarkerColorscale = require('../scatter/colorscale_calc'); var arraysToCalcdata = require('../scatter/arrays_to_calcdata'); var calcSelection = require('../scatter/calc_selection'); +var _ = require('../../lib')._; + module.exports = function calc(gd, trace) { var hasLocationData = Array.isArray(trace.locations); var len = hasLocationData ? trace.locations.length : trace.lon.length; @@ -40,5 +42,14 @@ module.exports = function calc(gd, trace) { calcMarkerColorscale(trace); calcSelection(calcTrace, trace); + if(len) { + calcTrace[0].t = { + labels: { + lat: _(gd, 'lat:') + ' ', + lon: _(gd, 'lon:') + ' ' + } + }; + } + return calcTrace; }; diff --git a/src/traces/scattergeo/hover.js b/src/traces/scattergeo/hover.js index 56aa35c359d..04e85b2ff7c 100644 --- a/src/traces/scattergeo/hover.js +++ b/src/traces/scattergeo/hover.js @@ -65,12 +65,12 @@ module.exports = function hoverPoints(pointData, xval, yval) { pointData.lat = lonlat[1]; pointData.color = getTraceColor(trace, di); - pointData.extraText = getExtraText(trace, di, geo.mockAxis); + pointData.extraText = getExtraText(trace, di, geo.mockAxis, cd[0].t.labels); return [pointData]; }; -function getExtraText(trace, pt, axis) { +function getExtraText(trace, pt, axis, labels) { var hoverinfo = pt.hi || trace.hoverinfo; var parts = hoverinfo === 'all' ? @@ -92,9 +92,9 @@ function getExtraText(trace, pt, axis) { } else if(hasLon && hasLat) { text.push('(' + format(pt.lonlat[0]) + ', ' + format(pt.lonlat[1]) + ')'); } else if(hasLon) { - text.push('lon: ' + format(pt.lonlat[0])); + text.push(labels.lon + format(pt.lonlat[0])); } else if(hasLat) { - text.push('lat: ' + format(pt.lonlat[1])); + text.push(labels.lat + format(pt.lonlat[1])); } if(hasText) { diff --git a/src/traces/scattermapbox/hover.js b/src/traces/scattermapbox/hover.js index d9805ed152a..3638e8ae18a 100644 --- a/src/traces/scattermapbox/hover.js +++ b/src/traces/scattermapbox/hover.js @@ -61,12 +61,12 @@ module.exports = function hoverPoints(pointData, xval, yval) { pointData.y1 = yc + rad; pointData.color = getTraceColor(trace, di); - pointData.extraText = getExtraText(trace, di); + pointData.extraText = getExtraText(trace, di, cd[0].t.labels); return [pointData]; }; -function getExtraText(trace, di) { +function getExtraText(trace, di, labels) { var hoverinfo = di.hi || trace.hoverinfo; var parts = hoverinfo.split('+'); var isAll = parts.indexOf('all') !== -1; @@ -85,9 +85,9 @@ function getExtraText(trace, di) { if(isAll || (hasLon && hasLat)) { text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')'); } else if(hasLon) { - text.push('lon: ' + format(lonlat[0])); + text.push(labels.lon + format(lonlat[0])); } else if(hasLat) { - text.push('lat: ' + format(lonlat[1])); + text.push(labels.lat + format(lonlat[1])); } if(isAll || parts.indexOf('text') !== -1) { diff --git a/src/traces/violin/calc.js b/src/traces/violin/calc.js index e4b0332824e..34064a9b01a 100644 --- a/src/traces/violin/calc.js +++ b/src/traces/violin/calc.js @@ -70,6 +70,8 @@ module.exports = function calc(gd, trace) { groupStats.maxCount = Math.max(groupStats.maxCount, vals.length); } + cd[0].t.labels.kde = Lib._(gd, 'kde:'); + return cd; }; diff --git a/src/traces/violin/hover.js b/src/traces/violin/hover.js index 32ea61ba63a..a6363cf2761 100644 --- a/src/traces/violin/hover.js +++ b/src/traces/violin/hover.js @@ -62,7 +62,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay kdePointData[pLetter + '0'] = pOnPath[0]; kdePointData[pLetter + '1'] = pOnPath[1]; kdePointData[vLetter + '0'] = kdePointData[vLetter + '1'] = vValPx; - kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal) + ', kde: ' + kdeVal.toFixed(3); + kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3); closeData.push(kdePointData); violinLineAttrs = {stroke: pointData.color}; diff --git a/tasks/bundle.js b/tasks/bundle.js index dd767f018ff..a6d7cd3dd64 100644 --- a/tasks/bundle.js +++ b/tasks/bundle.js @@ -1,7 +1,11 @@ +var path = require('path'); +var glob = require('glob'); + var constants = require('./util/constants'); var common = require('./util/common'); var _bundle = require('./util/browserify_wrapper'); var makeSchema = require('./util/make_schema'); +var wrapLocale = require('./util/wrap_locale'); /* * This script takes one argument * @@ -54,3 +58,13 @@ constants.partialBundlePaths.forEach(function(pathObj) { pathToMinBundle: pathObj.distMin }); }); + +// "Browserify" the locales +var localeGlob = path.join(constants.pathToLib, 'locale-*.js'); +glob(localeGlob, function(err, files) { + files.forEach(function(file) { + var outName = 'plotly-' + path.basename(file); + var outPath = path.join(constants.pathToDist, outName); + wrapLocale(file, outPath); + }); +}); diff --git a/tasks/find_locale_strings.js b/tasks/find_locale_strings.js new file mode 100644 index 00000000000..ff1da8552e3 --- /dev/null +++ b/tasks/find_locale_strings.js @@ -0,0 +1,98 @@ +var path = require('path'); +var fs = require('fs'); + +var falafel = require('falafel'); +var glob = require('glob'); + +var constants = require('./util/constants'); +var srcGlob = path.join(constants.pathToSrc, '**/*.js'); + +var common = require('./util/common'); + +var EXIT_CODE = 0; + +var localizeRE = /(^|[\.])(_|localize)$/; + +// main +findLocaleStrings(); + +function findLocaleStrings() { + glob(srcGlob, function(err, files) { + if(err) { + EXIT_CODE = 1; + console.log(err); + return; + } + + var dict = {}; + var hasTranslation = false; + var maxLen = 0; + + files.forEach(function(file) { + var code = fs.readFileSync(file, 'utf-8'); + var filePartialPath = file.substr(constants.pathToSrc.length); + + falafel(code, {locations: true}, function(node) { + // parse through code string looking for translated strings + // You may either assign `Lib.localize` to `_` and use that, or + // call `Lib.localize` directly. + if(node.type === 'CallExpression' && + (node.callee.name === '_' || node.callee.source() === 'Lib._') + ) { + var strNode = node.arguments[1]; + if(node.arguments.length !== 2) { + logError(file, node, 'Localize takes 2 args'); + } + if(strNode.type !== 'Literal') { + logError(file, node, 'Translated string must be a literal'); + } + if(!dict[strNode.value]) { + dict[strNode.value] = filePartialPath + ':' + node.loc.start.line; + maxLen = Math.max(maxLen, strNode.value.length); + hasTranslation = true; + } + } + + // make sure localize is the only thing we assign to a variable `_` + // NB: this does not preclude using `_` for an unused function arg + else if(node.type === 'VariableDeclarator' && node.id.name === '_') { + var src = node.init.source(); + if(!localizeRE.test(src)) { + logError(file, node, 'Use `_` only to mean localization'); + } + } + }); + }); + + if(!hasTranslation) { + console.error('Found no translations.'); + EXIT_CODE = 1; + } + + if(!EXIT_CODE) { + var strings = Object.keys(dict).sort().map(function(k) { + return k + spaces(maxLen - k.length) + ' // ' + dict[k]; + }).join('\n'); + common.writeFile(constants.pathToTranslationKeys, strings); + console.log('ok find_locale_strings'); + } + }); +} + +function logError(file, node, msg) { + console.error(file + ' [line ' + node.loc.start.line + '] ' + msg + + '\n ' + node.source()); + EXIT_CODE = 1; +} + +function spaces(len) { + var out = ''; + for(var i = 0; i < len; i++) out += ' '; + return out; +} + +process.on('exit', function() { + if(EXIT_CODE) { + throw new Error('find_locale_strings failed.'); + } +}); diff --git a/tasks/util/constants.js b/tasks/util/constants.js index 46f0ba357d4..20fa44fd695 100644 --- a/tasks/util/constants.js +++ b/tasks/util/constants.js @@ -42,6 +42,7 @@ module.exports = { pathToPlotlyDistWithMeta: path.join(pathToDist, 'plotly-with-meta.js'), pathToSchema: path.join(pathToDist, 'plot-schema.json'), + pathToTranslationKeys: path.join(pathToDist, 'translation-keys.txt'), partialBundleNames: partialBundleNames, partialBundlePaths: partialBundlePaths, diff --git a/tasks/util/wrap_locale.js b/tasks/util/wrap_locale.js new file mode 100644 index 00000000000..cfd86612fc7 --- /dev/null +++ b/tasks/util/wrap_locale.js @@ -0,0 +1,41 @@ +var fs = require('fs'); +var path = require('path'); + +var minify = require('minify-stream'); +var intoStream = require('into-stream'); + +var constants = require('./constants'); + +var prefix = 'Plotly.register('; +var suffix = ');'; + +var moduleMarker = 'module.exports = '; + +/** Wrap a locale json file into a standalone js file + * + * @param {string} pathToInput path to the locale json file + * @param {string} pathToOutput path to destination file + * + * Logs basename of bundle when completed. + */ +module.exports = function wrap_locale(pathToInput, pathToOutput) { + fs.readFile(pathToInput, 'utf8', function(err, data) { + var moduleStart = data.indexOf(moduleMarker) + moduleMarker.length; + var moduleEnd = data.indexOf(';', moduleStart); + + var rawOut = prefix + data.substr(moduleStart, moduleEnd - moduleStart) + suffix; + + intoStream(rawOut) + .pipe(minify(constants.uglifyOptions)) + .pipe(fs.createWriteStream(pathToOutput)) + .on('finish', function() { + logger(pathToOutput); + }); + }); +}; + +function logger(pathToOutput) { + var log = 'ok ' + path.basename(pathToOutput); + + console.log(log); +} diff --git a/test/image/mocks/geo_choropleth-text.json b/test/image/mocks/geo_choropleth-text.json index 083dae0fd85..d4a10cd441b 100644 --- a/test/image/mocks/geo_choropleth-text.json +++ b/test/image/mocks/geo_choropleth-text.json @@ -6,7 +6,6 @@ "text": [ "Angola", "Albania", - "Arab World", "United Arab Emirates", "Argentina", "Armenia", @@ -17,7 +16,6 @@ "Benin", "Bangladesh", "Bulgaria", - "Bahrain", "Bosnia and Herzegovina", "Belarus", "Bolivia", @@ -25,7 +23,6 @@ "Brunei Darussalam", "Botswana", "Canada", - "Central Europe and the Baltics", "Switzerland", "Chile", "China", @@ -34,7 +31,6 @@ "Congo, Rep.", "Colombia", "Costa Rica", - "Caribbean small states", "Cuba", "Cyprus", "Czech Republic", @@ -42,19 +38,12 @@ "Denmark", "Dominican Republic", "Algeria", - "East Asia & Pacific (developing only)", - "East Asia & Pacific (all income levels)", - "Europe & Central Asia (developing only)", - "Europe & Central Asia (all income levels)", "Ecuador", "Egypt, Arab Rep.", - "Euro area", "Eritrea", "Spain", "Estonia", "Ethiopia", - "European Union", - "Fragile and conflict affected situations", "Finland", "France", "Gabon", @@ -63,10 +52,7 @@ "Ghana", "Greece", "Guatemala", - "High income", - "Hong Kong SAR, China", "Honduras", - "Heavily indebted poor countries (HIPC)", "Croatia", "Haiti", "Hungary", @@ -88,44 +74,29 @@ "Korea, Rep.", "Kosovo", "Kuwait", - "Latin America & Caribbean (developing only)", "Lebanon", "Libya", - "Latin America & Caribbean (all income levels)", - "Least developed countries: UN classification", - "Low income", "Sri Lanka", - "Lower middle income", - "Low & middle income", "Lithuania", "Luxembourg", "Latvia", "Morocco", "Moldova", - "Middle East & North Africa (all income levels)", "Mexico", - "Middle income", "Macedonia, FYR", - "Malta", "Myanmar", - "Middle East & North Africa (developing only)", "Montenegro", "Mongolia", "Mozambique", "Malaysia", - "North America", "Namibia", "Nigeria", "Nicaragua", "Netherlands", - "High income: nonOECD", "Norway", "Nepal", "New Zealand", - "High income: OECD", - "OECD members", "Oman", - "Other small states", "Pakistan", "Panama", "Peru", @@ -137,16 +108,11 @@ "Qatar", "Romania", "Russian Federation", - "South Asia", "Saudi Arabia", "Sudan", "Senegal", - "Singapore", "El Salvador", "Serbia", - "Sub-Saharan Africa (developing only)", - "Sub-Saharan Africa (all income levels)", - "Small states", "Slovak Republic", "Slovenia", "Sweden", @@ -160,13 +126,11 @@ "Turkey", "Tanzania", "Ukraine", - "Upper middle income", "Uruguay", "United States", "Uzbekistan", "Venezuela, RB", "Vietnam", - "World", "Yemen, Rep.", "South Africa", "Congo, Dem. Rep.", @@ -177,7 +141,6 @@ "locations": [ "AGO", "ALB", - "ARB", "ARE", "ARG", "ARM", @@ -188,7 +151,6 @@ "BEN", "BGD", "BGR", - "BHR", "BIH", "BLR", "BOL", @@ -196,7 +158,6 @@ "BRN", "BWA", "CAN", - "CEB", "CHE", "CHL", "CHN", @@ -205,7 +166,6 @@ "COG", "COL", "CRI", - "CSS", "CUB", "CYP", "CZE", @@ -213,19 +173,12 @@ "DNK", "DOM", "DZA", - "EAP", - "EAS", - "ECA", - "ECS", "ECU", "EGY", - "EMU", "ERI", "ESP", "EST", "ETH", - "EUU", - "FCS", "FIN", "FRA", "GAB", @@ -234,10 +187,7 @@ "GHA", "GRC", "GTM", - "HIC", - "HKG", "HND", - "HPC", "HRV", "HTI", "HUN", @@ -259,44 +209,29 @@ "KOR", null, "KWT", - "LAC", "LBN", "LBY", - "LCN", - "LDC", - "LIC", "LKA", - "LMC", - "LMY", "LTU", "LUX", "LVA", "MAR", "MDA", - "MEA", "MEX", - "MIC", "MKD", - "MLT", "MMR", - "MNA", "MNE", "MNG", "MOZ", "MYS", - "NAC", "NAM", "NGA", "NIC", "NLD", - "NOC", "NOR", "NPL", "NZL", - "OEC", - "OED", "OMN", - "OSS", "PAK", "PAN", "PER", @@ -308,16 +243,11 @@ "QAT", "ROU", "RUS", - "SAS", "SAU", "SDN", "SEN", - "SGP", "SLV", "SRB", - "SSA", - "SSF", - "SST", "SVK", "SVN", "SWE", @@ -331,13 +261,11 @@ "TUR", "TZA", "UKR", - "UMC", "URY", "USA", "UZB", "VEN", "VNM", - "WLD", "YEM", "ZAF", "COD", @@ -347,7 +275,6 @@ "z": [ -639.491311425916, 21.2123434330386, - -174.09958727740897, -179.388449582104, -1.7041523393343299, 64.6472749649232, @@ -358,7 +285,6 @@ 43.7551733199028, 16.2437267991142, 40.8264927168205, - -87.1314080230412, 32.1996898013473, 85.0287198176801, -128.063878318709, @@ -366,7 +292,6 @@ -473.19072663497, 51.559108167064295, -57.762778129169995, - 37.8834751149095, 51.797306948137894, 70.20999876067239, 10.1199583054877, @@ -375,7 +300,6 @@ -1049.5396433485, -227.160178703599, 47.568660123804904, - -84.4378809914236, 53.2701580058226, 96.35067157026708, 28.2067516919418, @@ -383,19 +307,12 @@ -20.676751564727898, 89.0065422703776, -275.329807125617, - 3.51516098241885, - 15.9565539656918, - 4.834165156088309, - 4.47727995132693, -120.140677617521, -20.1443985137915, - 60.290587578546706, 21.9698628260283, 73.1513003612455, 11.451277242441599, 5.470357790113879, - 51.2509379809447, - -113.368328338844, 52.3663262919339, 48.1770056841254, -622.021499760279, @@ -404,10 +321,7 @@ 32.7335325055656, 65.79698915080941, 26.4857611165643, - 4.0046341022129, - 99.6180015703119, 51.4003670732292, - -19.7892791292931, 50.7301557348727, 28.012679109440302, 56.964989755763796, @@ -429,44 +343,29 @@ 82.02869222037559, 25.4365519637175, -313.221929844778, - -30.901110969748398, 96.75733945025999, -334.220009251031, - -28.5474513014272, - -53.2426615565718, - 3.76210562385273, 43.684467843411795, - -5.83892226829784, - -9.19186639970595, 78.45308301715771, 97.09329590523991, 54.4826301674269, 94.5657637772992, 96.2080909469791, - -140.35413698363502, -27.340652771459897, - -9.65202041824149, 43.949428786285296, - 99.6542636298781, -60.959456318897494, - -90.98129479054121, 24.078361622635498, -325.17346937593896, -22.1335972337041, -18.2148003028243, - 14.073188529997198, 79.576005073708, -121.28196341185301, 48.0103598393906, 16.3149384313268, - -97.9560487495735, -529.149021741409, 13.119464681168498, 7.69726241823141, - 29.2384675884995, - 28.277574597396697, -211.51288938573, - -138.461673060562, 23.731166221174696, 77.2777805633777, -0.8096633744691509, @@ -478,16 +377,11 @@ -515.549485382505, 21.575573631121003, -84.1182920382627, - 25.974081504352498, -180.230853147343, -111.00394800083599, 52.772861382765704, - 97.5436313612422, 46.294560725901604, 32.074863494552304, - -61.3730990794329, - -61.3730990794329, - -96.5210737821686, 65.18296765045, 48.4287551391239, 34.715333373425395, @@ -501,13 +395,11 @@ 69.3482069478227, 6.9525763336832, 40.5086856291844, - -11.1307458243133, 50.792767419753, 22.211408716366602, -25.967696793077604, -162.997187469107, -12.6903585180516, - -2.45491860900522, -131.876654010171, -14.705281572926301, -1.3275812135438898, diff --git a/test/jasmine/assets/modebar_button.js b/test/jasmine/assets/modebar_button.js index ad485f2601c..ba3c1182461 100644 --- a/test/jasmine/assets/modebar_button.js +++ b/test/jasmine/assets/modebar_button.js @@ -6,8 +6,14 @@ var modeBarButtons = require('../../../src/components/modebar/buttons'); module.exports = function selectButton(modeBar, name) { var button = {}; + var title = modeBarButtons[name].title; + + if(typeof title === 'function') { + title = title(modeBar.graphInfo); + } + var node = button.node = d3.select(modeBar.element) - .select('[data-title="' + modeBarButtons[name].title + '"]') + .select('[data-title="' + title + '"]') .node(); button.click = function() { diff --git a/test/jasmine/assets/supply_defaults.js b/test/jasmine/assets/supply_defaults.js new file mode 100644 index 00000000000..259950a647e --- /dev/null +++ b/test/jasmine/assets/supply_defaults.js @@ -0,0 +1,14 @@ +'use strict'; + +var Plots = require('@src/plots/plots'); + +/** + * supplyDefaults that fills in necessary _context + */ +module.exports = function supplyDefaults(gd) { + if(!gd._context) gd._context = {}; + if(!gd._context.locale) gd._context.locale = 'en'; + if(!gd._context.dictionaries) gd._context.dictionaries = {}; + + Plots.supplyDefaults(gd); +}; diff --git a/test/jasmine/tests/annotations_test.js b/test/jasmine/tests/annotations_test.js index 2f96fb22954..592677ae9f4 100644 --- a/test/jasmine/tests/annotations_test.js +++ b/test/jasmine/tests/annotations_test.js @@ -98,6 +98,11 @@ describe('Test annotations', function() { }); it('should clean *xclick* and *yclick* values', function() { + var errors = []; + spyOn(Loggers, 'error').and.callFake(function(msg) { + errors.push(msg); + }); + var layoutIn = { annotations: [{ clicktoshow: 'onoff', @@ -139,6 +144,7 @@ describe('Test annotations', function() { expect(layoutOut.annotations[1]._yclick).toBe(undefined, 'invalid date'); expect(layoutOut.annotations[2]._xclick).toBe(2, 'log'); expect(layoutOut.annotations[2]._yclick).toBe('A', 'category'); + expect(errors.length).toBe(1); }); }); }); diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index fb269708016..2e33ddab044 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -3,6 +3,7 @@ var d3 = require('d3'); var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); +var Loggers = require('@src/lib/loggers'); var Color = require('@src/components/color'); var tinycolor = require('tinycolor2'); @@ -14,6 +15,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var failTest = require('../assets/fail_test'); var selectButton = require('../assets/modebar_button'); +var supplyDefaults = require('../assets/supply_defaults'); describe('Test axes', function() { @@ -49,7 +51,7 @@ describe('Test axes', function() { type: 'date' }; - Plots.supplyDefaults(gd); + supplyDefaults(gd); Axes.swap(gd, [0]); @@ -80,7 +82,7 @@ describe('Test axes', function() { expectedLayoutAfter.xaxis.type = 'linear'; expectedLayoutAfter.yaxis.type = 'linear'; - Plots.supplyDefaults(gd); + supplyDefaults(gd); Axes.swap(gd, [0]); @@ -160,7 +162,7 @@ describe('Test axes', function() { {x: 5, y: 0.5, xref: 'x', yref: 'paper'} ]; - Plots.supplyDefaults(gd); + supplyDefaults(gd); Axes.swap(gd, [0, 1]); @@ -177,7 +179,8 @@ describe('Test axes', function() { beforeEach(function() { layoutOut = { _has: Plots._hasPlotType, - _basePlotModules: [] + _basePlotModules: [], + _dfltTitle: {x: 'x', y: 'y'} }; fullData = []; }); @@ -1186,6 +1189,11 @@ describe('Test axes', function() { expect(axOut.tick0).toBe('2000-01-01'); expect(axOut.dtick).toBe('M12'); + var errors = []; + spyOn(Loggers, 'error').and.callFake(function(msg) { + errors.push(msg); + }); + // now some stuff that shouldn't work, should give defaults [ ['next thursday', -1], @@ -1193,12 +1201,13 @@ describe('Test axes', function() { ['', 'M0.5'], ['', 'M-1'], ['', '2000-01-01'] - ].forEach(function(v) { + ].forEach(function(v, i) { axIn = {tick0: v[0], dtick: v[1]}; axOut = {}; mockSupplyDefaults(axIn, axOut, 'date'); expect(axOut.tick0).toBe('2000-01-01'); expect(axOut.dtick).toBe(oneDay); + expect(errors.length).toBe(i + 1); }); }); diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index b3f02aedcf2..68c9cbb9700 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -11,6 +11,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var checkTicks = require('../assets/custom_assertions').checkTicks; +var supplyAllDefaults = require('../assets/supply_defaults'); var d3 = require('d3'); @@ -1520,10 +1521,11 @@ function mockBarPlot(dataWithoutTraceType, layout) { var gd = { data: dataWithTraceType, layout: layout || {}, - calcdata: [] + calcdata: [], + _context: {locale: 'en', dictionaries: {}} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); var plotinfo = { diff --git a/test/jasmine/tests/carpet_test.js b/test/jasmine/tests/carpet_test.js index 4e2164188da..1bae596789d 100644 --- a/test/jasmine/tests/carpet_test.js +++ b/test/jasmine/tests/carpet_test.js @@ -14,6 +14,8 @@ var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); var assertHoverLabelContent = require('../assets/custom_assertions').assertHoverLabelContent; +var supplyAllDefaults = require('../assets/supply_defaults'); + describe('carpet supplyDefaults', function() { 'use strict'; @@ -114,13 +116,13 @@ describe('carpet supplyDefaults', function() { describe('supplyDefaults visibility check', function() { it('does not hide empty subplots', function() { var gd = {data: [], layout: {xaxis: {}}}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(true); }); it('does not hide axes with non-carpet traces', function() { var gd = {data: [{x: []}]}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(true); }); @@ -135,7 +137,7 @@ describe('supplyDefaults visibility check', function() { type: 'contourcarpet', z: [[1, 2, 3], [4, 5, 6]], }]}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(true); }); @@ -149,7 +151,7 @@ describe('supplyDefaults visibility check', function() { type: 'contourcarpet', z: [[1, 2, 3], [4, 5, 6]], }]}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(false); }); @@ -179,7 +181,7 @@ describe('supplyDefaults visibility check', function() { }] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(true); }); @@ -209,7 +211,7 @@ describe('supplyDefaults visibility check', function() { }] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.xaxis.visible).toBe(true); }); }); diff --git a/test/jasmine/tests/choropleth_test.js b/test/jasmine/tests/choropleth_test.js index 9c2465e5ff9..9dd6cf79b02 100644 --- a/test/jasmine/tests/choropleth_test.js +++ b/test/jasmine/tests/choropleth_test.js @@ -22,7 +22,8 @@ describe('Test choropleth', function() { var defaultColor = '#444', layout = { - font: Plots.layoutAttributes.font + font: Plots.layoutAttributes.font, + _dfltTitle: {colorbar: 'cb'} }; beforeEach(function() { @@ -171,7 +172,7 @@ describe('choropleth bad data', function() { afterEach(destroyGraphDiv); it('should not throw an error with bad locations', function(done) { - spyOn(Lib, 'warn'); + spyOn(Lib, 'log'); Plotly.newPlot(gd, [{ locations: ['canada', 0, null, '', 'utopia'], z: [1, 2, 3, 4, 5], @@ -179,8 +180,8 @@ describe('choropleth bad data', function() { type: 'choropleth' }]) .then(function() { - // only utopia warns - others are silently ignored - expect(Lib.warn).toHaveBeenCalledTimes(1); + // only utopia logs - others are silently ignored + expect(Lib.log).toHaveBeenCalledTimes(1); }) .catch(fail) .then(done); diff --git a/test/jasmine/tests/colorscale_test.js b/test/jasmine/tests/colorscale_test.js index 462d53c2a08..3eaa7c902d5 100644 --- a/test/jasmine/tests/colorscale_test.js +++ b/test/jasmine/tests/colorscale_test.js @@ -195,7 +195,8 @@ describe('Test colorscale:', function() { describe('handleDefaults (heatmap-like version)', function() { var handleDefaults = Colorscale.handleDefaults, layout = { - font: Plots.layoutAttributes.font + font: Plots.layoutAttributes.font, + _dfltTitle: {colorbar: 'cb'} }, opts = {prefix: '', cLetter: 'z'}; var traceIn, traceOut; @@ -265,7 +266,8 @@ describe('Test colorscale:', function() { describe('handleDefaults (scatter-like version)', function() { var handleDefaults = Colorscale.handleDefaults, layout = { - font: Plots.layoutAttributes.font + font: Plots.layoutAttributes.font, + _dfltTitle: {colorbar: 'cb'} }, opts = {prefix: 'marker.', cLetter: 'c'}; var traceIn, traceOut; diff --git a/test/jasmine/tests/command_test.js b/test/jasmine/tests/command_test.js index e3bef641bcf..ba061fefb3d 100644 --- a/test/jasmine/tests/command_test.js +++ b/test/jasmine/tests/command_test.js @@ -519,7 +519,7 @@ describe('component bindings', function() { it('logs a warning if unable to create an observer', function() { var warnings = 0; - spyOn(Lib, 'warn').and.callFake(function() { + spyOn(Lib, 'log').and.callFake(function() { warnings++; }); diff --git a/test/jasmine/tests/contour_test.js b/test/jasmine/tests/contour_test.js index 989a164eeb4..279b451bf46 100644 --- a/test/jasmine/tests/contour_test.js +++ b/test/jasmine/tests/contour_test.js @@ -10,6 +10,7 @@ var fail = require('../assets/fail_test'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var checkTicks = require('../assets/custom_assertions').checkTicks; +var supplyAllDefaults = require('../assets/supply_defaults'); describe('contour defaults', function() { @@ -20,7 +21,8 @@ describe('contour defaults', function() { var defaultColor = '#444', layout = { - font: Plots.layoutAttributes.font + font: Plots.layoutAttributes.font, + _dfltTitle: {colorbar: 'cb'} }; var supplyDefaults = Contour.supplyDefaults; @@ -64,7 +66,7 @@ describe('contour defaults', function() { y: [1, 2], z: [[1, 2], [3, 4]] }; - supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'}); + supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout)); // we always fill calendar attributes, because it's hard to tell if // we're on a date axis at this point. @@ -80,7 +82,7 @@ describe('contour defaults', function() { xcalendar: 'coptic', ycalendar: 'ethiopian' }; - supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'}); + supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout)); // we always fill calendar attributes, because it's hard to tell if // we're on a date axis at this point. @@ -182,7 +184,7 @@ describe('contour calc', function() { trace = Lib.extendFlat({}, base, opts), gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; var out = Contour.calc(gd, fullTrace)[0]; diff --git a/test/jasmine/tests/finance_test.js b/test/jasmine/tests/finance_test.js index 5abf1e455be..5df5ba59e10 100644 --- a/test/jasmine/tests/finance_test.js +++ b/test/jasmine/tests/finance_test.js @@ -5,6 +5,7 @@ var Lib = require('@src/lib'); var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); var mock0 = { open: [33.01, 33.31, 33.50, 32.06, 34.12, 33.05, 33.31, 33.50], @@ -29,7 +30,7 @@ describe('finance charts defaults:', function() { layout: layout }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); return gd; } @@ -389,7 +390,7 @@ describe('finance charts calc transforms:', function() { layout: layout || {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); return gd.calcdata.map(calcDatatoTrace); @@ -474,10 +475,10 @@ describe('finance charts calc transforms:', function() { expect(out[0].hoverinfo).toEqual('x+text+name'); expect(out[0].text[0]) - .toEqual('Open: 33.01
High: 34.2
Low: 31.7
Close: 34.1
A'); + .toEqual('open: 33.01
high: 34.2
low: 31.7
close: 34.1
A'); expect(out[0].hoverinfo).toEqual('x+text+name'); expect(out[1].text[0]) - .toEqual('Open: 33.31
High: 34.37
Low: 30.75
Close: 31.93
B'); + .toEqual('open: 33.31
high: 34.37
low: 30.75
close: 31.93
B'); expect(out[2].hoverinfo).toEqual('x+text'); expect(out[2].text[0]).toEqual('IMPORTANT'); @@ -487,10 +488,10 @@ describe('finance charts calc transforms:', function() { expect(out[4].hoverinfo).toEqual('text'); expect(out[4].text[0]) - .toEqual('Open: 33.01
High: 34.2
Low: 31.7
Close: 34.1'); + .toEqual('open: 33.01
high: 34.2
low: 31.7
close: 34.1'); expect(out[5].hoverinfo).toEqual('text'); expect(out[5].text[0]) - .toEqual('Open: 33.31
High: 34.37
Low: 30.75
Close: 31.93'); + .toEqual('open: 33.31
high: 34.37
low: 30.75
close: 31.93'); expect(out[6].hoverinfo).toEqual('x'); expect(out[6].text[0]).toEqual(''); diff --git a/test/jasmine/tests/fx_test.js b/test/jasmine/tests/fx_test.js index 54906198400..1c425b84357 100644 --- a/test/jasmine/tests/fx_test.js +++ b/test/jasmine/tests/fx_test.js @@ -1,9 +1,9 @@ var Plotly = require('@lib/index'); -var Plots = require('@src/plots/plots'); var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Fx defaults', function() { 'use strict'; @@ -14,7 +14,7 @@ describe('Fx defaults', function() { layout: layout || {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); return { data: gd._fullData, diff --git a/test/jasmine/tests/gl3daxes_test.js b/test/jasmine/tests/gl3daxes_test.js index fad1f8c222b..ea8f219e834 100644 --- a/test/jasmine/tests/gl3daxes_test.js +++ b/test/jasmine/tests/gl3daxes_test.js @@ -12,7 +12,8 @@ describe('Test Gl3dAxes', function() { font: 'Open Sans', scene: {id: 'scene'}, data: [{x: [], y: []}], - bgColor: '#fff' + bgColor: '#fff', + fullLayout: {_dfltTitle: {x: 'xxx', y: 'yyy', colorbar: 'cbbb'}} }; beforeEach(function() { diff --git a/test/jasmine/tests/gl3dlayout_test.js b/test/jasmine/tests/gl3dlayout_test.js index 4ae24334afd..cbcdaf72ea4 100644 --- a/test/jasmine/tests/gl3dlayout_test.js +++ b/test/jasmine/tests/gl3dlayout_test.js @@ -18,7 +18,7 @@ describe('Test Gl3d layout defaults', function() { var supplyLayoutDefaults = Gl3d.supplyLayoutDefaults; beforeEach(function() { - layoutOut = { _basePlotModules: ['gl3d'] }; + layoutOut = { _basePlotModules: ['gl3d'], _dfltTitle: {x: 'xxx', y: 'yyy', colorbar: 'cbbb'} }; // needs a scene-ref in a trace in order to be detected fullData = [ { type: 'scatter3d', scene: 'scene' }]; diff --git a/test/jasmine/tests/heatmap_test.js b/test/jasmine/tests/heatmap_test.js index 81e7737c736..70c86e4e816 100644 --- a/test/jasmine/tests/heatmap_test.js +++ b/test/jasmine/tests/heatmap_test.js @@ -9,6 +9,7 @@ var Heatmap = require('@src/traces/heatmap'); var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('heatmap supplyDefaults', function() { @@ -19,7 +20,8 @@ describe('heatmap supplyDefaults', function() { var defaultColor = '#444', layout = { - font: Plots.layoutAttributes.font + font: Plots.layoutAttributes.font, + _dfltTitle: {colorbar: 'cb'} }; var supplyDefaults = Heatmap.supplyDefaults; @@ -131,7 +133,7 @@ describe('heatmap supplyDefaults', function() { y: [1, 2], z: [[1, 2], [3, 4]] }; - supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'}); + supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendDeep({calendar: 'islamic'}, layout)); // we always fill calendar attributes, because it's hard to tell if // we're on a date axis at this point. @@ -147,7 +149,7 @@ describe('heatmap supplyDefaults', function() { xcalendar: 'coptic', ycalendar: 'ethiopian' }; - supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'}); + supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendDeep({calendar: 'islamic'}, layout)); // we always fill calendar attributes, because it's hard to tell if // we're on a date axis at this point. @@ -298,7 +300,7 @@ describe('heatmap calc', function() { trace = Lib.extendFlat({}, base, opts), gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; var fullLayout = gd._fullLayout; diff --git a/test/jasmine/tests/histogram2d_test.js b/test/jasmine/tests/histogram2d_test.js index 9529d3b380a..2ce0783e677 100644 --- a/test/jasmine/tests/histogram2d_test.js +++ b/test/jasmine/tests/histogram2d_test.js @@ -1,17 +1,23 @@ var Plotly = require('@lib/index'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); -var supplyDefaults = require('@src/traces/histogram2d/defaults'); +var supplyDefaultsRaw = require('@src/traces/histogram2d/defaults'); var calc = require('@src/traces/histogram2d/calc'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test histogram2d', function() { 'use strict'; + function supplyDefaults(traceIn, traceOut, defaultColor, layout) { + layout._dfltTitle = {colorbar: 'cb'}; + + return supplyDefaultsRaw(traceIn, traceOut, defaultColor, layout); + } + describe('supplyDefaults', function() { var traceIn, traceOut; @@ -115,7 +121,7 @@ describe('Test histogram2d', function() { trace = Lib.extendFlat({}, base, opts), gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; var out = calc(gd, fullTrace); diff --git a/test/jasmine/tests/histogram_test.js b/test/jasmine/tests/histogram_test.js index 60f4d57abd0..c4ce0a0c6bb 100644 --- a/test/jasmine/tests/histogram_test.js +++ b/test/jasmine/tests/histogram_test.js @@ -1,5 +1,4 @@ var Plotly = require('@lib/index'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var setConvert = require('@src/plots/cartesian/set_convert'); @@ -9,6 +8,7 @@ var getBinSpanLabelRound = require('@src/traces/histogram/bin_label_vals'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test histogram', function() { @@ -177,7 +177,7 @@ describe('Test histogram', function() { }); } - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; var out = calc(gd, fullTrace); diff --git a/test/jasmine/tests/lib_date_test.js b/test/jasmine/tests/lib_date_test.js index 2c5cd93e615..592d111ed22 100644 --- a/test/jasmine/tests/lib_date_test.js +++ b/test/jasmine/tests/lib_date_test.js @@ -1,6 +1,7 @@ var isNumeric = require('fast-isnumeric'); var Lib = require('@src/lib'); +var Loggers = require('@src/lib/loggers'); var calComponent = require('@src/components/calendars'); // use only the parts of world-calendars that we've imported for our tests @@ -360,6 +361,11 @@ describe('dates', function() { }); it('should fail numbers & js Dates out of range, and other bad objects', function() { + var errors = []; + spyOn(Loggers, 'error').and.callFake(function(msg) { + errors.push(msg); + }); + [ new Date(-20000, 0, 1), new Date(20000, 0, 1), @@ -372,6 +378,8 @@ describe('dates', function() { if(!isNumeric(+v)) expect(Lib.cleanDate(+v)).toBeUndefined(); expect(Lib.cleanDate(v, '2000-01-01')).toBe('2000-01-01'); }); + + expect(errors.length).toBe(16); }); it('should not alter valid date strings, even to truncate them', function() { diff --git a/test/jasmine/tests/localize_test.js b/test/jasmine/tests/localize_test.js new file mode 100644 index 00000000000..4d1989a65e7 --- /dev/null +++ b/test/jasmine/tests/localize_test.js @@ -0,0 +1,109 @@ +var Lib = require('@src/lib'); +var _ = Lib._; +var registry = require('@src/registry'); + +var Plotly = require('@lib'); +var createGraphDiv = require('../assets/create_graph_div'); +var destroyGraphDiv = require('../assets/destroy_graph_div'); +var failTest = require('../assets/fail_test'); + +describe('localization', function() { + 'use strict'; + + var gd; + var preregisteredDicts; + + beforeEach(function() { + gd = createGraphDiv(); + + // empty out any dictionaries we might register by default + preregisteredDicts = registry.localeRegistry; + registry.localeRegistry = {}; + }); + + afterEach(function() { + destroyGraphDiv(); + registry.localeRegistry = preregisteredDicts; + }); + + function plot(locale, dicts) { + var config = {}; + if(locale) config.locale = locale; + if(dicts) config.dictionaries = dicts; + + return Plotly.newPlot(gd, [{y: [1, 2]}], {}, config); + } + + it('uses the input string if no dictionaries are provided', function(done) { + plot() + .then(function() { + ['a', 'list of', 'Test strings 234!!!'].forEach(function(s) { + expect(_(gd, s)).toBe(s); + }); + }) + .catch(failTest) + .then(done); + }); + + it('uses the region first, then language (registered case)', function(done) { + plot('en-AU') + .then(function() { + expect(_(gd, 'dollar')).toBe('dollar'); + + // "en-GB" is registered first, so it gets copied into the base "en" + Plotly.register({moduleType: 'locale', name: 'en-GB', dictionary: {dollar: 'pound'}}); + Plotly.register({moduleType: 'locale', name: 'en-US', dictionary: {dollar: 'greenback', cent: 'penny'}}); + + expect(_(gd, 'dollar')).toBe('pound'); + // copying to the base happens at the dictionary level, so items missing + // from the first dictionary will not be picked up from later ones + expect(_(gd, 'cent')).toBe('cent'); + + // "en-AU" is exactly what we're looking for. + Plotly.register({moduleType: 'locale', name: 'en-AU', dictionary: {dollar: 'dollah'}}); + + expect(_(gd, 'dollar')).toBe('dollah'); + expect(_(gd, 'cent')).toBe('cent'); + }) + .catch(failTest) + .then(done); + }); + + it('gives higher precedence to region than context vs registered', function(done) { + // four dictionaries, highest to lowest priority + // hopefully nobody will supply this many conflicting dictionaries, but + // if they do, this is what should happen! + var ctx_fr_QC = { + a: 'a-ctx-QC' + }; + Plotly.register({moduleType: 'locale', name: 'fr-QC', dictionary: { + a: 'a-reg-QC', b: 'b-reg-QC' + }}); + var ctx_fr = { + a: 'a-ctx', b: 'b-ctx', c: 'c-ctx' + }; + Plotly.register({moduleType: 'locale', name: 'fr', dictionary: { + a: 'a-reg', b: 'b-reg', c: 'c-reg', d: 'd-reg' + }}); + + plot('fr-QC', {fr: ctx_fr, 'fr-QC': ctx_fr_QC}) + .then(function() { + expect(_(gd, 'a')).toBe('a-ctx-QC'); + expect(_(gd, 'b')).toBe('b-reg-QC'); + expect(_(gd, 'c')).toBe('c-ctx'); + expect(_(gd, 'd')).toBe('d-reg'); + expect(_(gd, 'e')).toBe('e'); + }) + .catch(failTest) + .then(done); + }); + + it('does not generate an automatic base language dictionary in context', function(done) { + plot('fr', {'fr-QC': {fries: 'poutine'}}) + .then(function() { + expect(_(gd, 'fries')).toBe('fries'); + }) + .catch(failTest) + .then(done); + }); +}); diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js index 68590653f1f..67dff7bae4e 100644 --- a/test/jasmine/tests/mapbox_test.js +++ b/test/jasmine/tests/mapbox_test.js @@ -1,5 +1,4 @@ var Plotly = require('@lib'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var constants = require('@src/plots/mapbox/constants'); @@ -10,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); var failTest = require('../assets/fail_test'); +var supplyAllDefaults = require('../assets/supply_defaults'); var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; @@ -180,7 +180,7 @@ describe('mapbox defaults', function() { layout: {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullLayout.dragmode).toBe('pan'); }); }); diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 1b37fd74b25..425732ef006 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -37,7 +37,9 @@ describe('ModeBar', function() { displaylogo: true, displayModeBar: true, modeBarButtonsToRemove: [], - modeBarButtonsToAdd: [] + modeBarButtonsToAdd: [], + locale: 'en', + dictionaries: {} } }; } diff --git a/test/jasmine/tests/parcoords_test.js b/test/jasmine/tests/parcoords_test.js index a632a4d21d2..1b8772d354c 100644 --- a/test/jasmine/tests/parcoords_test.js +++ b/test/jasmine/tests/parcoords_test.js @@ -8,6 +8,7 @@ var attributes = require('@src/traces/parcoords/attributes'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); +var supplyAllDefaults = require('../assets/supply_defaults'); // mock with two dimensions (one panel); special case, e.g. left and right panel is obv. the same var mock2 = require('@mocks/gl2d_parcoords_2.json'); @@ -33,7 +34,7 @@ describe('parcoords initialization tests', function() { it('should not coerce trace opacity', function() { var gd = Lib.extendDeep({}, mock1); - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].opacity).toBeUndefined(); }); @@ -46,7 +47,7 @@ describe('parcoords initialization tests', function() { color: 'blue' }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var expected = { family: 'Gravitas', @@ -169,7 +170,7 @@ describe('parcoords initialization tests', function() { function _calc(trace) { var gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; Parcoords.calc(gd, fullTrace); diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 59a02aa79c5..6974f8ff63a 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -16,6 +16,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var checkTicks = require('../assets/custom_assertions').checkTicks; +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test plot api', function() { @@ -516,7 +517,7 @@ describe('Test plot api', function() { subroutines[m].calls.reset(); }); - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); return gd; } @@ -576,7 +577,7 @@ describe('Test plot api', function() { }); function mockDefaultsAndCalc(gd) { - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); gd.calcdata = gd._fullData.map(function(trace) { return [{x: 1, y: 1, trace: trace}]; }); diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js index 355a7daf07b..b6f31cab997 100644 --- a/test/jasmine/tests/plots_test.js +++ b/test/jasmine/tests/plots_test.js @@ -5,6 +5,7 @@ var Lib = require('@src/lib'); var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test Plots', function() { @@ -20,7 +21,7 @@ describe('Test Plots', function() { } }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd.layout.height).toBe(height); expect(gd._fullLayout).toBeDefined(); expect(gd._fullLayout.height).toBe(height); @@ -70,7 +71,7 @@ describe('Test Plots', function() { layout: newLayout }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].z).toBe(newData[0].z); expect(gd._fullData[1].z).toBe(newData[1].z); @@ -94,7 +95,7 @@ describe('Test Plots', function() { var data = [trace0, trace1]; var gd = { data: data }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd.data).toBe(data); @@ -116,7 +117,7 @@ describe('Test Plots', function() { function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) { spyOn(Plots, 'sanitizeMargins').and.callThrough(); - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(Plots.sanitizeMargins).toHaveBeenCalledTimes(1); } @@ -159,7 +160,12 @@ describe('Test Plots', function() { layoutOut, expected; - var supplyLayoutDefaults = Plots.supplyLayoutGlobalDefaults; + function supplyLayoutDefaults(layoutIn, layoutOut) { + layoutOut._dfltTitle = { + plot: 'ppplot' + }; + return Plots.supplyLayoutGlobalDefaults(layoutIn, layoutOut); + } beforeEach(function() { layoutOut = {}; diff --git a/test/jasmine/tests/range_slider_test.js b/test/jasmine/tests/range_slider_test.js index 1cd215ab62c..3cdfa6a2237 100644 --- a/test/jasmine/tests/range_slider_test.js +++ b/test/jasmine/tests/range_slider_test.js @@ -1,5 +1,4 @@ var Plotly = require('@lib/index'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var setConvert = require('@src/plots/cartesian/set_convert'); @@ -11,6 +10,7 @@ var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); +var supplyAllDefaults = require('../assets/supply_defaults'); var TOL = 6; @@ -585,7 +585,7 @@ describe('the range slider', function() { } }; - Plots.supplyDefaults(mock); + supplyAllDefaults(mock); expect(mock._fullLayout.xaxis.rangeslider.visible).toBe(true); expect(mock._fullLayout.yaxis.fixedrange).toBe(true); @@ -603,7 +603,7 @@ describe('the range slider', function() { } }; - Plots.supplyDefaults(mock); + supplyAllDefaults(mock); expect(mock._fullLayout.xaxis.rangeslider.visible).toBe(true); expect(mock._fullLayout.yaxis.fixedrange).toBe(false); diff --git a/test/jasmine/tests/sankey_test.js b/test/jasmine/tests/sankey_test.js index 33e36cee22d..573d3aa57c2 100644 --- a/test/jasmine/tests/sankey_test.js +++ b/test/jasmine/tests/sankey_test.js @@ -4,7 +4,6 @@ var Lib = require('@src/lib'); var d3 = require('d3'); var mock = require('@mocks/sankey_energy.json'); var mockDark = require('@mocks/sankey_energy_dark.json'); -var Plots = require('@src/plots/plots'); var Sankey = require('@src/traces/sankey'); var createGraphDiv = require('../assets/create_graph_div'); @@ -12,6 +11,7 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle; +var supplyAllDefaults = require('../assets/supply_defaults'); describe('sankey tests', function() { @@ -87,7 +87,7 @@ describe('sankey tests', function() { it('should not coerce trace opacity', function() { var gd = Lib.extendDeep({}, mock); - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].opacity).toBeUndefined(); }); @@ -223,7 +223,7 @@ describe('sankey tests', function() { function _calc(trace) { var gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; Sankey.calc(gd, fullTrace); return fullTrace; @@ -231,30 +231,19 @@ describe('sankey tests', function() { var base = { type: 'sankey' }; - it('circularity is detected', function() { + describe('remove nodes if encountering circularity', function() { + var errors; - var errors = []; - spyOn(Lib, 'error').and.callFake(function(msg) { - errors.push(msg); + beforeEach(function() { + errors = []; + spyOn(Lib, 'error').and.callFake(function(msg) { + errors.push(msg); + }); }); - _calc(Lib.extendDeep({}, base, { - node: { - label: ['a', 'b', 'c'] - }, - link: { - value: [1, 1, 1], - source: [0, 1, 2], - target: [1, 2, 0] - } - })); - - expect(errors.length).toEqual(1); - }); - - describe('remove nodes if encountering circularity', function() { - it('removing a single self-pointing node', function() { + expect(errors.length).toBe(0); + var fullTrace = _calc(Lib.extendDeep({}, base, { node: { label: ['a'] @@ -270,10 +259,12 @@ describe('sankey tests', function() { expect(fullTrace.link.value).toEqual([], 'link value(s) removed'); expect(fullTrace.link.source).toEqual([], 'link source(s) removed'); expect(fullTrace.link.target).toEqual([], 'link target(s) removed'); - + expect(errors.length).toBe(1); }); it('removing everything if detecting a circle', function() { + expect(errors.length).toBe(0); + var fullTrace = _calc(Lib.extendDeep({}, base, { node: { label: ['a', 'b', 'c', 'd', 'e'] @@ -289,7 +280,7 @@ describe('sankey tests', function() { expect(fullTrace.link.value).toEqual([], 'link value(s) removed'); expect(fullTrace.link.source).toEqual([], 'link source(s) removed'); expect(fullTrace.link.target).toEqual([], 'link target(s) removed'); - + expect(errors.length).toBe(1); }); }); }); @@ -390,7 +381,7 @@ describe('sankey tests', function() { _hover(404, 302); assertLabel( - ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'], + ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'], ['rgb(148, 103, 189)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)'] ); }) @@ -398,7 +389,7 @@ describe('sankey tests', function() { _hover(450, 300); assertLabel( - ['Source: Solid', 'Target: Industry', '46TWh'], + ['source: Solid', 'target: Industry', '46TWh'], ['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)'] ); @@ -408,7 +399,7 @@ describe('sankey tests', function() { _hover(404, 302); assertLabel( - ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'], + ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'], ['rgb(148, 103, 189)', 'rgb(255, 255, 255)', 13, 'Roboto', 'rgb(255, 255, 255)'] ); }) @@ -416,7 +407,7 @@ describe('sankey tests', function() { _hover(450, 300); assertLabel( - ['Source: Solid', 'Target: Industry', '46TWh'], + ['source: Solid', 'target: Industry', '46TWh'], ['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Roboto', 'rgb(255, 255, 255)'] ); @@ -431,7 +422,7 @@ describe('sankey tests', function() { _hover(404, 302); assertLabel( - ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'], + ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'], ['rgb(255, 0, 0)', 'rgb(0, 0, 255)', 20, 'Roboto', 'rgb(0, 0, 0)'] ); }) @@ -439,7 +430,7 @@ describe('sankey tests', function() { _hover(450, 300); assertLabel( - ['Source: Solid', 'Target: Industry', '46TWh'], + ['source: Solid', 'target: Industry', '46TWh'], ['rgb(255, 0, 0)', 'rgb(0, 0, 255)', 20, 'Roboto', 'rgb(0, 0, 0)'] ); }) @@ -463,7 +454,7 @@ describe('sankey tests', function() { _hover(450, 300); assertLabel( - ['Source: Solid', 'Target: Industry', '46TWh'], + ['source: Solid', 'target: Industry', '46TWh'], ['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)'] ); }) diff --git a/test/jasmine/tests/scattergeo_test.js b/test/jasmine/tests/scattergeo_test.js index c1a51f4b23c..1c9e107e020 100644 --- a/test/jasmine/tests/scattergeo_test.js +++ b/test/jasmine/tests/scattergeo_test.js @@ -1,5 +1,4 @@ var Plotly = require('@lib'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var BADNUM = require('@src/constants/numerical').BADNUM; @@ -14,6 +13,7 @@ var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; var assertHoverLabelContent = customAssertions.assertHoverLabelContent; var fail = require('../assets/fail_test'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test scattergeo defaults', function() { var traceIn, @@ -90,11 +90,12 @@ describe('Test scattergeo calc', function() { var trace = Lib.extendFlat({}, base, opts); var gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; return ScatterGeo.calc(gd, fullTrace).map(function(obj) { delete obj.i; + delete obj.t; return obj; }); } @@ -347,15 +348,15 @@ describe('scattergeo bad data', function() { afterEach(destroyGraphDiv); it('should not throw an error with bad locations', function(done) { - spyOn(Lib, 'warn'); + spyOn(Lib, 'log'); Plotly.newPlot(gd, [{ locations: ['canada', 0, null, '', 'utopia'], locationmode: 'country names', type: 'scattergeo' }]) .then(function() { - // only utopia warns - others are silently ignored - expect(Lib.warn).toHaveBeenCalledTimes(1); + // only utopia logs - others are silently ignored + expect(Lib.log).toHaveBeenCalledTimes(1); }) .catch(fail) .then(done); diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js index 729b4cd6abc..bc355973a2e 100644 --- a/test/jasmine/tests/scattermapbox_test.js +++ b/test/jasmine/tests/scattermapbox_test.js @@ -8,6 +8,7 @@ var convert = require('@src/traces/scattermapbox/convert'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); +var supplyAllDefaults = require('../assets/supply_defaults'); var mouseEvent = require('../assets/mouse_event'); var click = require('../assets/click'); @@ -112,7 +113,7 @@ describe('scattermapbox convert', function() { function _convert(trace) { var gd = { data: [trace] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var fullTrace = gd._fullData[0]; Plots.doCalcdata(gd, fullTrace); diff --git a/test/jasmine/tests/scatterternary_test.js b/test/jasmine/tests/scatterternary_test.js index ad46a26303f..4396be60261 100644 --- a/test/jasmine/tests/scatterternary_test.js +++ b/test/jasmine/tests/scatterternary_test.js @@ -1,5 +1,4 @@ var Plotly = require('@lib'); -var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var ScatterTernary = require('@src/traces/scatterternary'); @@ -8,6 +7,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var customAssertions = require('../assets/custom_assertions'); +var supplyAllDefaults = require('../assets/supply_defaults'); var assertClip = customAssertions.assertClip; var assertNodeDisplay = customAssertions.assertNodeDisplay; @@ -149,7 +149,7 @@ describe('scatterternary defaults', function() { }; var gd = {data: [traceIn, {}]}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].hoverinfo).toBe('all'); }); @@ -163,7 +163,7 @@ describe('scatterternary defaults', function() { }; var gd = {data: [traceIn]}; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].hoverinfo).toBe('a+b+c+text'); }); diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js index 38bf19fb1ba..0010264a62e 100644 --- a/test/jasmine/tests/select_test.js +++ b/test/jasmine/tests/select_test.js @@ -889,7 +889,7 @@ describe('Test select box and lasso per trace:', function() { [[350, 200], [400, 250]], function() { assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]); - assertSelectedPoints({0: [54, 68]}); + assertSelectedPoints({0: [43, 54]}); assertRanges([[-19.11, 63.06], [7.31, 53.72]]); }, [280, 190], @@ -904,7 +904,7 @@ describe('Test select box and lasso per trace:', function() { [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]], function() { assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]); - assertSelectedPoints({0: [54, 68]}); + assertSelectedPoints({0: [43, 54]}); assertLassoPoints([ [-19.11, 63.06], [5.50, 65.25], [7.31, 53.72], [-12.90, 51.70], [-19.11, 63.06] ]); diff --git a/test/jasmine/tests/surface_test.js b/test/jasmine/tests/surface_test.js index 96aa26f0193..b7d23716bc7 100644 --- a/test/jasmine/tests/surface_test.js +++ b/test/jasmine/tests/surface_test.js @@ -10,7 +10,7 @@ describe('Test surface', function() { var supplyDefaults = Surface.supplyDefaults; var defaultColor = '#444', - layout = {}; + layout = {_dfltTitle: {colorbar: 'cb'}}; var traceIn, traceOut; @@ -155,7 +155,7 @@ describe('Test surface', function() { traceIn = { z: [[1, 2, 3], [2, 1, 2]] }; - supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'}); + supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout)); // we always fill calendar attributes, because it's hard to tell if // we're on a date axis at this point. diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index ddc2676d4cb..5e599cd593e 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -1,12 +1,12 @@ var Plotly = require('@lib/index'); var Lib = require('@src/lib'); -var Plots = require('@src/plots/plots'); var Table = require('@src/traces/table'); var attributes = require('@src/traces/table/attributes'); var cn = require('@src/traces/table/constants').cn; var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var supplyAllDefaults = require('../assets/supply_defaults'); var mockMulti = require('@mocks/table_latex_multitrace.json'); @@ -35,7 +35,7 @@ describe('table initialization tests', function() { it('should not coerce trace opacity', function() { var gd = Lib.extendDeep({}, mock1); - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); expect(gd._fullData[0].opacity).toBeUndefined(); }); @@ -50,7 +50,7 @@ describe('table initialization tests', function() { color: 'blue' }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); var expected = { family: 'Gravitas', diff --git a/test/jasmine/tests/transform_filter_test.js b/test/jasmine/tests/transform_filter_test.js index 7caee22f0e6..cc7034c739d 100644 --- a/test/jasmine/tests/transform_filter_test.js +++ b/test/jasmine/tests/transform_filter_test.js @@ -7,6 +7,7 @@ var Lib = require('@src/lib'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var customAssertions = require('../assets/custom_assertions'); +var supplyAllDefaults = require('../assets/supply_defaults'); var assertDims = customAssertions.assertDims; var assertStyle = customAssertions.assertStyle; @@ -97,7 +98,7 @@ describe('filter transforms calc:', function() { layout: layout || {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); return gd.calcdata.map(calcDatatoTrace); diff --git a/test/jasmine/tests/transform_multi_test.js b/test/jasmine/tests/transform_multi_test.js index 94deb0f5505..829d84569db 100644 --- a/test/jasmine/tests/transform_multi_test.js +++ b/test/jasmine/tests/transform_multi_test.js @@ -7,6 +7,7 @@ var Lib = require('@src/lib'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var customAssertions = require('../assets/custom_assertions'); +var supplyAllDefaults = require('../assets/supply_defaults'); var assertDims = customAssertions.assertDims; var assertStyle = customAssertions.assertStyle; @@ -866,7 +867,7 @@ describe('supplyDefaults with groupby + filter', function() { layout: layout || {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); return gd.calcdata.map(calcDatatoTrace); diff --git a/test/jasmine/tests/transform_sort_test.js b/test/jasmine/tests/transform_sort_test.js index cddb44a7acc..38e2be3b79d 100644 --- a/test/jasmine/tests/transform_sort_test.js +++ b/test/jasmine/tests/transform_sort_test.js @@ -7,6 +7,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); +var supplyAllDefaults = require('../assets/supply_defaults'); describe('Test sort transform defaults:', function() { function _supply(trace, layout) { @@ -76,7 +77,7 @@ describe('Test sort transform calc:', function() { layout: layout || {} }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); return gd.calcdata.map(calcDatatoTrace); diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 755d2b20e19..0e57bb51318 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -9,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var fail = require('../assets/fail_test'); var mouseEvent = require('../assets/mouse_event'); +var supplyAllDefaults = require('../assets/supply_defaults'); var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelContent = customAssertions.assertHoverLabelContent; @@ -152,7 +153,7 @@ describe('Test violin calc:', function() { layout: layout || {}, calcdata: [] }; - Plots.supplyDefaults(gd); + supplyAllDefaults(gd); Plots.doCalcdata(gd); cd = gd.calcdata[0]; fullLayout = gd._fullLayout;