diff --git a/src/components/annotations/click.js b/src/components/annotations/click.js index addadd1ac5f..b2f300fb9be 100644 --- a/src/components/annotations/click.js +++ b/src/components/annotations/click.js @@ -6,11 +6,9 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; -var Plotly = require('../../plotly'); - +var Registry = require('../../registry'); module.exports = { hasClickToShow: hasClickToShow, @@ -59,7 +57,7 @@ function onClick(gd, hoverData) { update['annotations[' + offSet[i] + '].visible'] = false; } - return Plotly.update(gd, {}, update); + return Registry.call('update', gd, {}, update); } /* diff --git a/src/components/annotations/draw.js b/src/components/annotations/draw.js index 2c4660a524c..d5b2ce2e287 100644 --- a/src/components/annotations/draw.js +++ b/src/components/annotations/draw.js @@ -6,12 +6,11 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var d3 = require('d3'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); @@ -21,10 +20,8 @@ var Fx = require('../fx'); var svgTextUtils = require('../../lib/svg_text_utils'); var setCursor = require('../../lib/setcursor'); var dragElement = require('../dragelement'); - var drawArrowHead = require('./draw_arrow_head'); - // Annotations are stored in gd.layout.annotations, an array of objects // index can point to one item in this array, // or non-numeric to simply add a new one @@ -594,7 +591,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { }); }, doneFn: function() { - Plotly.relayout(gd, update); + Registry.call('relayout', gd, update); var notesBox = document.querySelector('.js-notes-box-panel'); if(notesBox) notesBox.redraw(notesBox.selectedObj); } @@ -676,7 +673,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { }, doneFn: function() { setCursor(annTextGroupInner); - Plotly.relayout(gd, update); + Registry.call('relayout', gd, update); var notesBox = document.querySelector('.js-notes-box-panel'); if(notesBox) notesBox.redraw(notesBox.selectedObj); } @@ -701,7 +698,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) { update[ya._name + '.autorange'] = true; } - Plotly.relayout(gd, update); + Registry.call('relayout', gd, update); }); } else annText.call(textLayout); diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index f7a78a3d26a..9ad1ac4017b 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -12,7 +12,6 @@ var d3 = require('d3'); var tinycolor = require('tinycolor2'); -var Plotly = require('../../plotly'); var Plots = require('../../plots/plots'); var Registry = require('../../registry'); var Axes = require('../../plots/cartesian/axes'); @@ -588,9 +587,11 @@ module.exports = function draw(gd, id) { setCursor(container); if(xf !== undefined && yf !== undefined) { - Plotly.restyle(gd, + Registry.call('restyle', + gd, {'colorbar.x': xf, 'colorbar.y': yf}, - getTrace().index); + getTrace().index + ); } } }); diff --git a/src/components/dragelement/index.js b/src/components/dragelement/index.js index 90785a2eb0d..0c008b6e76b 100644 --- a/src/components/dragelement/index.js +++ b/src/components/dragelement/index.js @@ -13,7 +13,7 @@ var mouseOffset = require('mouse-event-offset'); var hasHover = require('has-hover'); var supportsPassive = require('has-passive-events'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var constants = require('../../plots/cartesian/constants'); @@ -278,7 +278,7 @@ dragElement.coverSlip = coverSlip; function finishDrag(gd) { gd._dragging = false; - if(gd._replotPending) Plotly.plot(gd); + if(gd._replotPending) Registry.call('plot', gd); } function pointerOffset(e) { diff --git a/src/components/errorbars/index.js b/src/components/errorbars/index.js index 502140b7539..59c223c443d 100644 --- a/src/components/errorbars/index.js +++ b/src/components/errorbars/index.js @@ -6,18 +6,57 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; -var errorBars = module.exports = {}; +var Lib = require('../../lib'); +var overrideAll = require('../../plot_api/edit_types').overrideAll; + +var attributes = require('./attributes'); +var calc = require('./calc'); + +var xyAttrs = { + error_x: Lib.extendFlat({}, attributes), + error_y: Lib.extendFlat({}, attributes) +}; +delete xyAttrs.error_x.copy_zstyle; +delete xyAttrs.error_y.copy_zstyle; +delete xyAttrs.error_y.copy_ystyle; + +var xyzAttrs = { + error_x: Lib.extendFlat({}, attributes), + error_y: Lib.extendFlat({}, attributes), + error_z: Lib.extendFlat({}, attributes) +}; +delete xyzAttrs.error_x.copy_ystyle; +delete xyzAttrs.error_y.copy_ystyle; +delete xyzAttrs.error_z.copy_ystyle; +delete xyzAttrs.error_z.copy_zstyle; + +module.exports = { + moduleType: 'component', + name: 'errorbars', -errorBars.attributes = require('./attributes'); + schema: { + traces: { + scatter: xyAttrs, + bar: xyAttrs, + histogram: xyAttrs, + scatter3d: overrideAll(xyzAttrs, 'calc', 'nested'), + scattergl: overrideAll(xyAttrs, 'calc', 'nested') + } + }, -errorBars.supplyDefaults = require('./defaults'); + supplyDefaults: require('./defaults'), -errorBars.calc = require('./calc'); + calc: calc, + calcFromTrace: calcFromTrace, -errorBars.calcFromTrace = function(trace, layout) { + plot: require('./plot'), + style: require('./style'), + hoverInfo: hoverInfo +}; + +function calcFromTrace(trace, layout) { var x = trace.x || [], y = trace.y || [], len = x.length || y.length; @@ -33,19 +72,15 @@ errorBars.calcFromTrace = function(trace, layout) { calcdataMock[0].trace = trace; - errorBars.calc({ + calc({ calcdata: [calcdataMock], _fullLayout: layout }); return calcdataMock; -}; +} -errorBars.plot = require('./plot'); - -errorBars.style = require('./style'); - -errorBars.hoverInfo = function(calcPoint, trace, hoverPoint) { +function hoverInfo(calcPoint, trace, hoverPoint) { if((trace.error_y || {}).visible) { hoverPoint.yerr = calcPoint.yh - calcPoint.y; if(!trace.error_y.symmetric) hoverPoint.yerrneg = calcPoint.y - calcPoint.ys; @@ -54,4 +89,4 @@ errorBars.hoverInfo = function(calcPoint, trace, hoverPoint) { hoverPoint.xerr = calcPoint.xh - calcPoint.x; if(!trace.error_x.symmetric) hoverPoint.xerrneg = calcPoint.x - calcPoint.xs; } -}; +} diff --git a/src/plots/grid.js b/src/components/grid/index.js similarity index 96% rename from src/plots/grid.js rename to src/components/grid/index.js index 7e1f75722a6..064bbd93272 100644 --- a/src/plots/grid.js +++ b/src/components/grid/index.js @@ -8,13 +8,12 @@ 'use strict'; -var Lib = require('../lib'); -var domainAttrs = require('./domain').attributes; -var counterRegex = require('../lib/regex').counter; -var cartesianIdRegex = require('./cartesian/constants').idRegex; +var Lib = require('../../lib'); +var counterRegex = require('../../lib/regex').counter; +var domainAttrs = require('../../plots/domain').attributes; +var cartesianIdRegex = require('../../plots/cartesian/constants').idRegex; - -var gridAttrs = exports.attributes = { +var gridAttrs = { rows: { valType: 'integer', min: 1, @@ -168,7 +167,7 @@ var gridAttrs = exports.attributes = { // the shape of the grid - this needs to be done BEFORE supplyDataDefaults // so that non-subplot traces can place themselves in the grid -exports.sizeDefaults = function(layoutIn, layoutOut) { +function sizeDefaults(layoutIn, layoutOut) { var gridIn = layoutIn.grid; if(!gridIn) return; @@ -211,7 +210,7 @@ exports.sizeDefaults = function(layoutIn, layoutOut) { x: fillGridPositions('x', coerce, hasSubplotGrid ? 0.2 : 0.1, columns), y: fillGridPositions('y', coerce, hasSubplotGrid ? 0.3 : 0.1, rows, reversed) }; -}; +} // coerce x or y sizing attributes and return an array of domains for this direction function fillGridPositions(axLetter, coerce, dfltGap, len, reversed) { @@ -232,7 +231,7 @@ function fillGridPositions(axLetter, coerce, dfltGap, len, reversed) { // the (cartesian) contents of the grid - this needs to happen AFTER supplyDataDefaults // so that we know what cartesian subplots are available -exports.contentDefaults = function(layoutIn, layoutOut) { +function contentDefaults(layoutIn, layoutOut) { var gridOut = layoutOut.grid; // make sure we got to the end of handleGridSizing if(!gridOut || !gridOut._domains) return; @@ -368,7 +367,7 @@ exports.contentDefaults = function(layoutIn, layoutOut) { } } } -}; +} function fillGridAxes(axesIn, axesAllowed, len, axisMap, axLetter) { var out = new Array(len); @@ -397,3 +396,16 @@ function fillGridAxes(axesIn, axesAllowed, len, axisMap, axLetter) { return out; } + +module.exports = { + moduleType: 'component', + name: 'grid', + + schema: { + layout: {grid: gridAttrs} + }, + + layoutAttributes: gridAttrs, + sizeDefaults: sizeDefaults, + contentDefaults: contentDefaults +}; diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 3ba1a94194b..609573a851b 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -10,7 +10,6 @@ var d3 = require('d3'); -var Plotly = require('../../plotly'); var Lib = require('../../lib'); var Plots = require('../../plots/plots'); var Registry = require('../../registry'); @@ -339,7 +338,7 @@ module.exports = function draw(gd) { }, doneFn: function() { if(xf !== undefined && yf !== undefined) { - Plotly.relayout(gd, {'legend.x': xf, 'legend.y': yf}); + Registry.call('relayout', gd, {'legend.x': xf, 'legend.y': yf}); } }, clickFn: function(numClicks, e) { @@ -431,7 +430,7 @@ function drawTexts(g, gd) { update.name = text; } - return Plotly.restyle(gd, update, traceIndex); + return Registry.call('restyle', gd, update, traceIndex); }); } else { text.call(textLayout); diff --git a/src/components/legend/handle_click.js b/src/components/legend/handle_click.js index 73b7feb8965..b12bf50e8e3 100644 --- a/src/components/legend/handle_click.js +++ b/src/components/legend/handle_click.js @@ -8,7 +8,6 @@ 'use strict'; -var Plotly = require('../../plotly'); var Lib = require('../../lib'); var Registry = require('../../registry'); @@ -112,7 +111,7 @@ module.exports = function handleClick(g, gd, numClicks) { } } - Plotly.relayout(gd, 'hiddenlabels', hiddenSlices); + Registry.call('relayout', gd, 'hiddenlabels', hiddenSlices); } else { var hasLegendgroup = legendgroup && legendgroup.length; var traceIndicesInGroup = []; @@ -218,6 +217,6 @@ module.exports = function handleClick(g, gd, numClicks) { } } - Plotly.restyle(gd, attrUpdate, attrIndices); + Registry.call('restyle', gd, attrUpdate, attrIndices); } }; diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 73ebb04db55..97496258eaa 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -9,14 +9,12 @@ 'use strict'; -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var axisIds = require('../../plots/cartesian/axis_ids'); var Lib = require('../../lib'); -var downloadImage = require('../../snapshot/download'); var Icons = require('../../../build/ploticon'); - var _ = Lib._; var modeBarButtons = module.exports = {}; @@ -61,7 +59,7 @@ modeBarButtons.toImage = { format = 'svg'; } - downloadImage(gd, {'format': format}) + Registry.call('downloadImage', gd, {'format': format}) .then(function(filename) { Lib.notifier(_(gd, 'Snapshot succeeded') + ' - ' + filename, 'long'); }) @@ -250,7 +248,7 @@ function handleCartesian(gd, ev) { aobj[astr] = val; } - Plotly.relayout(gd, aobj); + Registry.call('relayout', gd, aobj); } modeBarButtons.zoom3d = { @@ -306,7 +304,7 @@ function handleDrag3d(gd, ev) { var val2d = (val === 'pan') ? val : 'zoom'; layoutUpdate.dragmode = val2d; - Plotly.relayout(gd, layoutUpdate); + Registry.call('relayout', gd, layoutUpdate); } modeBarButtons.resetCameraDefault3d = { @@ -345,7 +343,7 @@ function handleCamera3d(gd, ev) { } } - Plotly.relayout(gd, aobj); + Registry.call('relayout', gd, aobj); } modeBarButtons.hoverClosest3d = { @@ -406,7 +404,7 @@ function handleHover3d(gd, ev) { button._previousVal = Lib.extendDeep({}, currentSpikes); } - Plotly.relayout(gd, layoutUpdate); + Registry.call('relayout', gd, layoutUpdate); } modeBarButtons.zoomInGeo = { @@ -462,7 +460,7 @@ function handleGeo(gd, ev) { var scale = geoLayout.projection.scale; var newScale = (val === 'in') ? 2 * scale : 0.5 * scale; - Plotly.relayout(gd, id + '.projection.scale', newScale); + Registry.call('relayout', gd, id + '.projection.scale', newScale); } else if(attr === 'reset') { resetView(gd, 'geo'); } @@ -501,7 +499,7 @@ function toggleHover(gd) { var newHover = gd._fullLayout.hovermode ? false : onHoverVal; - Plotly.relayout(gd, 'hovermode', newHover); + Registry.call('relayout', gd, 'hovermode', newHover); } // buttons when more then one plot types are present @@ -556,7 +554,7 @@ modeBarButtons.toggleSpikelines = { var aobj = setSpikelineVisibility(gd); - Plotly.relayout(gd, aobj); + Registry.call('relayout', gd, aobj); } }; @@ -603,5 +601,5 @@ function resetView(gd, subplotType) { } } - Plotly.relayout(gd, aObj); + Registry.call('relayout', gd, aObj); } diff --git a/src/components/rangeselector/draw.js b/src/components/rangeselector/draw.js index c5730804d24..f729267eed8 100644 --- a/src/components/rangeselector/draw.js +++ b/src/components/rangeselector/draw.js @@ -6,12 +6,11 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var d3 = require('d3'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var Color = require('../color'); var Drawing = require('../drawing'); @@ -69,7 +68,7 @@ module.exports = function draw(gd) { button.on('click', function() { if(gd._dragged) return; - Plotly.relayout(gd, update); + Registry.call('relayout', gd, update); }); button.on('mouseover', function() { diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 2690438d9b1..61d6e9f50fe 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -10,7 +10,7 @@ var d3 = require('d3'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var Lib = require('../../lib'); @@ -25,7 +25,6 @@ var setCursor = require('../../lib/setcursor'); var constants = require('./constants'); - module.exports = function(gd) { var fullLayout = gd._fullLayout, rangeSliderData = makeRangeSliderData(fullLayout); @@ -262,7 +261,7 @@ function setDataRange(rangeSlider, gd, axisOpts, opts) { dataMax = clamp(opts.p2d(opts._pixelMax)); window.requestAnimationFrame(function() { - Plotly.relayout(gd, axisOpts._name + '.range', [dataMin, dataMax]); + Registry.call('relayout', gd, axisOpts._name + '.range', [dataMin, dataMax]); }); } diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js index 1af2788580f..271e37c4861 100644 --- a/src/components/shapes/draw.js +++ b/src/components/shapes/draw.js @@ -9,7 +9,7 @@ 'use strict'; -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); var Color = require('../color'); @@ -213,7 +213,7 @@ function setupDragElement(gd, shapePath, shapeOptions, index) { function endDrag() { setCursor(shapePath); - Plotly.relayout(gd, update); + Registry.call('relayout', gd, update); } function moveShape(dx, dy) { diff --git a/src/components/titles/index.js b/src/components/titles/index.js index 2fd89dd409e..8b66cbacaf3 100644 --- a/src/components/titles/index.js +++ b/src/components/titles/index.js @@ -12,8 +12,8 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); -var Plotly = require('../../plotly'); var Plots = require('../../plots/plots'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var Drawing = require('../drawing'); var Color = require('../color'); @@ -237,8 +237,11 @@ Titles.draw = function(gd, titleClass, options) { el.call(svgTextUtils.makeEditable, {gd: gd}) .on('edit', function(text) { - if(traceIndex !== undefined) Plotly.restyle(gd, prop, text, traceIndex); - else Plotly.relayout(gd, prop, text); + if(traceIndex !== undefined) { + Registry.call('restyle', gd, prop, text, traceIndex); + } else { + Registry.call('relayout', gd, prop, text); + } }) .on('cancel', function() { this.text(this.attr('data-unformatted')) diff --git a/src/core.js b/src/core.js index c6c6e452353..6fb5cd193d0 100644 --- a/src/core.js +++ b/src/core.js @@ -8,12 +8,6 @@ 'use strict'; -/* - * Export the plotly.js API methods. - */ - -var Plotly = require('./plotly'); - // package version injected by `npm run preprocess` exports.version = '1.34.0'; @@ -26,34 +20,28 @@ require('../build/plotcss'); // inject default MathJax config require('./fonts/mathjax_config'); -// plot api -exports.plot = Plotly.plot; -exports.newPlot = Plotly.newPlot; -exports.restyle = Plotly.restyle; -exports.relayout = Plotly.relayout; -exports.redraw = Plotly.redraw; -exports.update = Plotly.update; -exports.react = Plotly.react; -exports.extendTraces = Plotly.extendTraces; -exports.prependTraces = Plotly.prependTraces; -exports.addTraces = Plotly.addTraces; -exports.deleteTraces = Plotly.deleteTraces; -exports.moveTraces = Plotly.moveTraces; -exports.purge = Plotly.purge; -exports.setPlotConfig = require('./plot_api/set_plot_config'); -exports.register = require('./plot_api/register'); -exports.toImage = require('./plot_api/to_image'); -exports.downloadImage = require('./snapshot/download'); -exports.validate = require('./plot_api/validate'); -exports.addFrames = Plotly.addFrames; -exports.deleteFrames = Plotly.deleteFrames; -exports.animate = Plotly.animate; +// include registry module and expose register method +var Registry = require('./registry'); +var register = exports.register = Registry.register; + +// expose plot api methods +var plotApi = require('./plot_api'); +var methodNames = Object.keys(plotApi); +for(var i = 0; i < methodNames.length; i++) { + var name = methodNames[i]; + exports[name] = plotApi[name]; + register({ + moduleType: 'apiMethod', + name: name, + fn: plotApi[name] + }); +} // scatter is the only trace included by default -exports.register(require('./traces/scatter')); +register(require('./traces/scatter')); // register all registrable components modules -exports.register([ +register([ require('./components/fx'), require('./components/legend'), require('./components/annotations'), @@ -63,11 +51,13 @@ exports.register([ require('./components/updatemenus'), require('./components/sliders'), require('./components/rangeslider'), - require('./components/rangeselector') + require('./components/rangeselector'), + require('./components/grid'), + require('./components/errorbars') ]); // locales en and en-US are required for default behavior -exports.register([ +register([ require('./locale-en'), require('./locale-en-us') ]); @@ -76,7 +66,7 @@ exports.register([ exports.Icons = require('../build/ploticon'); // unofficial 'beta' plot methods, use at your own risk -exports.Plots = Plotly.Plots; +exports.Plots = require('./plots/plots'); exports.Fx = require('./components/fx'); exports.Snapshot = require('./snapshot'); exports.PlotSchema = require('./plot_api/plot_schema'); diff --git a/src/plot_api/index.js b/src/plot_api/index.js new file mode 100644 index 00000000000..1dc7da478d0 --- /dev/null +++ b/src/plot_api/index.js @@ -0,0 +1,33 @@ +/** +* Copyright 2012-2018, 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 main = require('./plot_api'); + +exports.plot = main.plot; +exports.newPlot = main.newPlot; +exports.restyle = main.restyle; +exports.relayout = main.relayout; +exports.redraw = main.redraw; +exports.update = main.update; +exports.react = main.react; +exports.extendTraces = main.extendTraces; +exports.prependTraces = main.prependTraces; +exports.addTraces = main.addTraces; +exports.deleteTraces = main.deleteTraces; +exports.moveTraces = main.moveTraces; +exports.purge = main.purge; +exports.addFrames = main.addFrames; +exports.deleteFrames = main.deleteFrames; +exports.animate = main.animate; +exports.setPlotConfig = main.setPlotConfig; + +exports.toImage = require('./to_image'); +exports.validate = require('./validate'); +exports.downloadImage = require('../snapshot/download'); diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index c52bdc44cd5..74d57421e75 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -14,7 +14,6 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); var hasHover = require('has-hover'); -var Plotly = require('../plotly'); var Lib = require('../lib'); var Events = require('../lib/events'); var Queue = require('../lib/queue'); @@ -25,12 +24,13 @@ var Plots = require('../plots/plots'); var Polar = require('../plots/polar/legacy'); var initInteractions = require('../plots/cartesian/graph_interact'); +var Axes = require('../plots/cartesian/axes'); var Drawing = require('../components/drawing'); var Color = require('../components/color'); -var ErrorBars = require('../components/errorbars'); var xmlnsNamespaces = require('../constants/xmlns_namespaces'); var svgTextUtils = require('../lib/svg_text_utils'); +var defaultConfig = require('./plot_config'); var manageArrays = require('./manage_arrays'); var helpers = require('./helpers'); var subroutines = require('./subroutines'); @@ -66,7 +66,7 @@ var numericNameWarningCountLimit = 5; * object containing `data`, `layout`, `config`, and `frames` members * */ -Plotly.plot = function(gd, data, layout, config) { +exports.plot = function(gd, data, layout, config) { var frames; gd = Lib.getGraphDiv(gd); @@ -94,7 +94,7 @@ Plotly.plot = function(gd, data, layout, config) { function addFrames() { if(frames) { - return Plotly.addFrames(gd, frames); + return exports.addFrames(gd, frames); } } @@ -176,7 +176,7 @@ Plotly.plot = function(gd, data, layout, config) { Drawing.initGradients(gd); // save initial show spikes once per graph - if(graphWasEmpty) Plotly.Axes.saveShowSpikeInitial(gd); + if(graphWasEmpty) Axes.saveShowSpikeInitial(gd); // prepare the data and find the autorange @@ -312,7 +312,7 @@ Plotly.plot = function(gd, data, layout, config) { } // calc and autorange for errorbars - ErrorBars.calc(gd); + Registry.getComponentMethod('errorbars', 'calc')(gd); // TODO: autosize extra for text markers and images // see https://github.com/plotly/plotly.js/issues/1111 @@ -327,24 +327,24 @@ Plotly.plot = function(gd, data, layout, config) { function doAutoRangeAndConstraints() { if(gd._transitioning) return; - var axList = Plotly.Axes.list(gd, '', true); + var axList = Axes.list(gd, '', true); for(var i = 0; i < axList.length; i++) { var ax = axList[i]; cleanAxisConstraints(gd, ax); - Plotly.Axes.doAutoRange(ax); + Axes.doAutoRange(ax); } enforceAxisConstraints(gd); // store initial ranges *after* enforcing constraints, otherwise // we will never look like we're at the initial ranges - if(graphWasEmpty) Plotly.Axes.saveRangeInitial(gd); + if(graphWasEmpty) Axes.saveRangeInitial(gd); } // draw ticks, titles, and calculate axis scaling (._b, ._m) function drawAxes() { - return Plotly.Axes.doTicks(gd, 'redraw'); + return Axes.doTicks(gd, 'redraw'); } // Now plot the data @@ -448,6 +448,10 @@ Plotly.plot = function(gd, data, layout, config) { }); }; +exports.setPlotConfig = function setPlotConfig(obj) { + return Lib.extendFlat(defaultConfig, obj); +}; + function setBackground(gd, bgColor) { try { gd._fullLayout._paper.style('background', bgColor); @@ -462,7 +466,7 @@ function opaqueSetBackground(gd, bgColor) { } function setPlotContext(gd, config) { - if(!gd._context) gd._context = Lib.extendDeep({}, Plotly.defaultConfig); + if(!gd._context) gd._context = Lib.extendDeep({}, defaultConfig); var context = gd._context; var i, keys, key; @@ -628,7 +632,7 @@ function plotPolar(gd, data, layout) { } // convenience function to force a full redraw, mostly for use by plotly.js -Plotly.redraw = function(gd) { +exports.redraw = function(gd) { gd = Lib.getGraphDiv(gd); if(!Lib.isPlotDiv(gd)) { @@ -639,7 +643,7 @@ Plotly.redraw = function(gd) { helpers.cleanLayout(gd.layout); gd.calcdata = undefined; - return Plotly.plot(gd).then(function() { + return exports.plot(gd).then(function() { gd.emit('plotly_redraw'); return gd; }); @@ -653,14 +657,14 @@ Plotly.redraw = function(gd) { * @param {Object} layout * @param {Object} config */ -Plotly.newPlot = function(gd, data, layout, config) { +exports.newPlot = function(gd, data, layout, config) { gd = Lib.getGraphDiv(gd); // remove gl contexts Plots.cleanPlot([], {}, gd._fullData || {}, gd._fullLayout || {}); Plots.purge(gd); - return Plotly.plot(gd, data, layout, config); + return exports.plot(gd, data, layout, config); }; /** @@ -988,7 +992,7 @@ function concatTypedArray(arr0, arr1) { * @param {Number|Object} [maxPoints] Number of points for trace window after lengthening. * */ -Plotly.extendTraces = function extendTraces(gd, update, indices, maxPoints) { +exports.extendTraces = function extendTraces(gd, update, indices, maxPoints) { gd = Lib.getGraphDiv(gd); function updateArray(target, insert, maxp) { @@ -1039,14 +1043,14 @@ Plotly.extendTraces = function extendTraces(gd, update, indices, maxPoints) { } var undo = spliceTraces(gd, update, indices, maxPoints, updateArray); - var promise = Plotly.redraw(gd); + var promise = exports.redraw(gd); var undoArgs = [gd, undo.update, indices, undo.maxPoints]; - Queue.add(gd, Plotly.prependTraces, undoArgs, extendTraces, arguments); + Queue.add(gd, exports.prependTraces, undoArgs, extendTraces, arguments); return promise; }; -Plotly.prependTraces = function prependTraces(gd, update, indices, maxPoints) { +exports.prependTraces = function prependTraces(gd, update, indices, maxPoints) { gd = Lib.getGraphDiv(gd); function updateArray(target, insert, maxp) { @@ -1096,9 +1100,9 @@ Plotly.prependTraces = function prependTraces(gd, update, indices, maxPoints) { } var undo = spliceTraces(gd, update, indices, maxPoints, updateArray); - var promise = Plotly.redraw(gd); + var promise = exports.redraw(gd); var undoArgs = [gd, undo.update, indices, undo.maxPoints]; - Queue.add(gd, Plotly.extendTraces, undoArgs, prependTraces, arguments); + Queue.add(gd, exports.extendTraces, undoArgs, prependTraces, arguments); return promise; }; @@ -1112,11 +1116,11 @@ Plotly.prependTraces = function prependTraces(gd, update, indices, maxPoints) { * @param {Number[]|Number} [newIndices=[gd.data.length]] Locations to add traces * */ -Plotly.addTraces = function addTraces(gd, traces, newIndices) { +exports.addTraces = function addTraces(gd, traces, newIndices) { gd = Lib.getGraphDiv(gd); var currentIndices = [], - undoFunc = Plotly.deleteTraces, + undoFunc = exports.deleteTraces, redoFunc = addTraces, undoArgs = [gd, currentIndices], redoArgs = [gd, traces], // no newIndices here @@ -1151,7 +1155,7 @@ Plotly.addTraces = function addTraces(gd, traces, newIndices) { // if the user didn't define newIndices, they just want the traces appended // i.e., we can simply redraw and be done if(typeof newIndices === 'undefined') { - promise = Plotly.redraw(gd); + promise = exports.redraw(gd); Queue.add(gd, undoFunc, undoArgs, redoFunc, redoArgs); return promise; } @@ -1177,7 +1181,7 @@ Plotly.addTraces = function addTraces(gd, traces, newIndices) { // this requires some extra work that moveTraces will do Queue.startSequence(gd); Queue.add(gd, undoFunc, undoArgs, redoFunc, redoArgs); - promise = Plotly.moveTraces(gd, currentIndices, newIndices); + promise = exports.moveTraces(gd, currentIndices, newIndices); Queue.stopSequence(gd); return promise; }; @@ -1189,11 +1193,11 @@ Plotly.addTraces = function addTraces(gd, traces, newIndices) { * @param {Object[]} gd.data The array of traces we're removing from * @param {Number|Number[]} indices The indices */ -Plotly.deleteTraces = function deleteTraces(gd, indices) { +exports.deleteTraces = function deleteTraces(gd, indices) { gd = Lib.getGraphDiv(gd); var traces = [], - undoFunc = Plotly.addTraces, + undoFunc = exports.addTraces, redoFunc = deleteTraces, undoArgs = [gd, traces, indices], redoArgs = [gd, indices], @@ -1218,7 +1222,7 @@ Plotly.deleteTraces = function deleteTraces(gd, indices) { traces.push(deletedTrace); } - var promise = Plotly.redraw(gd); + var promise = exports.redraw(gd); Queue.add(gd, undoFunc, undoArgs, redoFunc, redoArgs); return promise; @@ -1255,7 +1259,7 @@ Plotly.deleteTraces = function deleteTraces(gd, indices) { * // reorder all traces (assume there are 5--a, b, c, d, e) * Plotly.moveTraces(gd, [b, d, e, a, c]) // same as 'move to end' */ -Plotly.moveTraces = function moveTraces(gd, currentIndices, newIndices) { +exports.moveTraces = function moveTraces(gd, currentIndices, newIndices) { gd = Lib.getGraphDiv(gd); var newData = [], @@ -1316,7 +1320,7 @@ Plotly.moveTraces = function moveTraces(gd, currentIndices, newIndices) { gd.data = newData; - var promise = Plotly.redraw(gd); + var promise = exports.redraw(gd); Queue.add(gd, undoFunc, undoArgs, redoFunc, redoArgs); return promise; @@ -1352,7 +1356,7 @@ Plotly.moveTraces = function moveTraces(gd, currentIndices, newIndices) { * If the array is too short, it will wrap around (useful for * style files that want to specify cyclical default values). */ -Plotly.restyle = function restyle(gd, astr, val, _traces) { +exports.restyle = function restyle(gd, astr, val, _traces) { gd = Lib.getGraphDiv(gd); helpers.clearPromiseQueue(gd); @@ -1383,7 +1387,7 @@ Plotly.restyle = function restyle(gd, astr, val, _traces) { var seq = []; if(flags.fullReplot) { - seq.push(Plotly.plot); + seq.push(exports.plot); } else { seq.push(Plots.previousPromises); @@ -1436,7 +1440,7 @@ function _restyle(gd, aobj, traces) { // for autoranging multiple axes function addToAxlist(axid) { - var axName = Plotly.Axes.id2name(axid); + var axName = Axes.id2name(axid); if(axlist.indexOf(axName) === -1) axlist.push(axName); } @@ -1635,7 +1639,7 @@ function _restyle(gd, aobj, traces) { // swap the data attributes of the relevant x and y axes? if(['swapxyaxes', 'orientationaxes'].indexOf(ai) !== -1) { - Plotly.Axes.swap(gd, traces); + Axes.swap(gd, traces); } // swap hovermode if set to "compare x/y data" @@ -1672,7 +1676,7 @@ function _restyle(gd, aobj, traces) { // do we need to force a recalc? var autorangeOn = false; - var axList = Plotly.Axes.list(gd); + var axList = Axes.list(gd); for(i = 0; i < axList.length; i++) { if(axList[i].autorange) { autorangeOn = true; @@ -1717,7 +1721,7 @@ function _restyle(gd, aobj, traces) { * attribute object `{astr1: val1, astr2: val2 ...}` * allows setting multiple attributes simultaneously */ -Plotly.relayout = function relayout(gd, astr, val) { +exports.relayout = function relayout(gd, astr, val) { gd = Lib.getGraphDiv(gd); helpers.clearPromiseQueue(gd); @@ -1783,7 +1787,7 @@ function _relayout(gd, aobj) { var layout = gd.layout, fullLayout = gd._fullLayout, keys = Object.keys(aobj), - axes = Plotly.Axes.list(gd), + axes = Axes.list(gd), arrayEdits = {}, arrayStr, i, @@ -2127,7 +2131,7 @@ function _relayout(gd, aobj) { function refAutorange(gd, obj, axLetter) { if(!Lib.isPlainObject(obj)) return false; var axRef = obj[axLetter + 'ref'] || axLetter, - ax = Plotly.Axes.getFromId(gd, axRef); + ax = Axes.getFromId(gd, axRef); if(!ax && axRef.charAt(0) === axLetter) { // fall back on the primary axis in case we've referenced a @@ -2137,7 +2141,7 @@ function refAutorange(gd, obj, axLetter) { // The only thing this is used for is to determine whether to // do a full `recalc`, so the only ill effect of this error is // to waste some time. - ax = Plotly.Axes.getFromId(gd, axLetter); + ax = Axes.getFromId(gd, axLetter); } return (ax || {}).autorange; } @@ -2157,7 +2161,7 @@ function refAutorange(gd, obj, axLetter) { * integer or array of integers for the traces to alter (all if omitted) * */ -Plotly.update = function update(gd, traceUpdate, layoutUpdate, _traces) { +exports.update = function update(gd, traceUpdate, layoutUpdate, _traces) { gd = Lib.getGraphDiv(gd); helpers.clearPromiseQueue(gd); @@ -2195,10 +2199,10 @@ Plotly.update = function update(gd, traceUpdate, layoutUpdate, _traces) { gd.data = undefined; gd.layout = undefined; - seq.push(function() { return Plotly.plot(gd, data, layout); }); + seq.push(function() { return exports.plot(gd, data, layout); }); } else if(restyleFlags.fullReplot) { - seq.push(Plotly.plot); + seq.push(exports.plot); } else if(relayoutFlags.layoutReplot) { seq.push(subroutines.layoutReplot); @@ -2259,10 +2263,10 @@ Plotly.update = function update(gd, traceUpdate, layoutUpdate, _traces) { * object containing `data`, `layout`, `config`, and `frames` members * */ -Plotly.react = function(gd, data, layout, config) { +exports.react = function(gd, data, layout, config) { var frames, plotDone; - function addFrames() { return Plotly.addFrames(gd, frames); } + function addFrames() { return exports.addFrames(gd, frames); } gd = Lib.getGraphDiv(gd); @@ -2271,7 +2275,7 @@ Plotly.react = function(gd, data, layout, config) { // you can use this as the initial draw as well as to update if(!Lib.isPlotDiv(gd) || !oldFullData || !oldFullLayout) { - plotDone = Plotly.newPlot(gd, data, layout, config); + plotDone = exports.newPlot(gd, data, layout, config); } else { @@ -2324,7 +2328,7 @@ Plotly.react = function(gd, data, layout, config) { if(restyleFlags.fullReplot || relayoutFlags.layoutReplot || configChanged) { gd._fullLayout._skipDefaults = true; - seq.push(Plotly.plot); + seq.push(exports.plot); } else { for(var componentType in relayoutFlags.arrays) { @@ -2399,8 +2403,8 @@ function diffData(gd, oldFullData, newFullData, immutable) { for(i = 0; i < oldFullData.length; i++) { trace = newFullData[i]; diffOpts.autoranged = trace.xaxis ? ( - Plotly.Axes.getFromId(gd, trace.xaxis).autorange || - Plotly.Axes.getFromId(gd, trace.yaxis).autorange + Axes.getFromId(gd, trace.xaxis).autorange || + Axes.getFromId(gd, trace.yaxis).autorange ) : false; getDiffFlags(oldFullData[i], trace, [], diffOpts); } @@ -2661,7 +2665,7 @@ function diffConfig(oldConfig, newConfig) { * @param {object} animationOpts * configuration for the animation */ -Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { +exports.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { gd = Lib.getGraphDiv(gd); if(!Lib.isPlotDiv(gd)) { @@ -3025,7 +3029,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) { * provided, an index will be provided in serial order. If already used, the frame * will be overwritten. */ -Plotly.addFrames = function(gd, frameList, indices) { +exports.addFrames = function(gd, frameList, indices) { gd = Lib.getGraphDiv(gd); if(frameList === null || frameList === undefined) { @@ -3154,7 +3158,7 @@ Plotly.addFrames = function(gd, frameList, indices) { * @param {array of integers} frameList * list of integer indices of frames to be deleted */ -Plotly.deleteFrames = function(gd, frameList) { +exports.deleteFrames = function(gd, frameList) { gd = Lib.getGraphDiv(gd); if(!Lib.isPlotDiv(gd)) { @@ -3198,7 +3202,7 @@ Plotly.deleteFrames = function(gd, frameList) { * @param {string id or DOM element} gd * the id or DOM element of the graph container div */ -Plotly.purge = function purge(gd) { +exports.purge = function purge(gd) { gd = Lib.getGraphDiv(gd); var fullLayout = gd._fullLayout || {}, diff --git a/src/plot_api/register.js b/src/plot_api/register.js deleted file mode 100644 index 7ee96d5d259..00000000000 --- a/src/plot_api/register.js +++ /dev/null @@ -1,101 +0,0 @@ -/** -* Copyright 2012-2018, 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'); -var Lib = require('../lib'); - - -module.exports = function register(_modules) { - if(!_modules) { - throw new Error('No argument passed to Plotly.register.'); - } - else if(_modules && !Array.isArray(_modules)) { - _modules = [_modules]; - } - - for(var i = 0; i < _modules.length; i++) { - var newModule = _modules[i]; - - if(!newModule) { - throw new Error('Invalid module was attempted to be registered!'); - } - - switch(newModule.moduleType) { - case 'trace': - registerTraceModule(newModule); - break; - - case 'transform': - registerTransformModule(newModule); - break; - - case 'component': - registerComponentModule(newModule); - break; - - case 'locale': - Registry.registerLocale(newModule); - break; - - default: - throw new Error('Invalid module was attempted to be registered!'); - } - } -}; - -function registerTraceModule(newModule) { - Registry.register(newModule, newModule.name, newModule.categories, newModule.meta); - - if(!Registry.subplotsRegistry[newModule.basePlotModule.name]) { - Registry.registerSubplot(newModule.basePlotModule); - } -} - -function registerTransformModule(newModule) { - if(typeof newModule.name !== 'string') { - throw new Error('Transform module *name* must be a string.'); - } - - var prefix = 'Transform module ' + newModule.name; - - var hasTransform = typeof newModule.transform === 'function', - hasCalcTransform = typeof newModule.calcTransform === 'function'; - - - if(!hasTransform && !hasCalcTransform) { - throw new Error(prefix + ' is missing a *transform* or *calcTransform* method.'); - } - - if(hasTransform && hasCalcTransform) { - Lib.log([ - prefix + ' has both a *transform* and *calcTransform* methods.', - 'Please note that all *transform* methods are executed', - 'before all *calcTransform* methods.' - ].join(' ')); - } - - if(!Lib.isPlainObject(newModule.attributes)) { - Lib.log(prefix + ' registered without an *attributes* object.'); - } - - if(typeof newModule.supplyDefaults !== 'function') { - Lib.log(prefix + ' registered without a *supplyDefaults* method.'); - } - - Registry.registerTransform(newModule); -} - -function registerComponentModule(newModule) { - if(typeof newModule.name !== 'string') { - throw new Error('Component module *name* must be a string.'); - } - - Registry.registerComponent(newModule); -} diff --git a/src/plot_api/set_plot_config.js b/src/plot_api/set_plot_config.js deleted file mode 100644 index 63ba1a38e69..00000000000 --- a/src/plot_api/set_plot_config.js +++ /dev/null @@ -1,24 +0,0 @@ -/** -* Copyright 2012-2018, 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 Plotly = require('../plotly'); -var Lib = require('../lib'); - -/** - * Extends the plot config - * - * @param {object} configObj partial plot configuration object - * to extend the current plot configuration. - * - */ -module.exports = function setPlotConfig(configObj) { - return Lib.extendFlat(Plotly.defaultConfig, configObj); -}; diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 0a3c2e8a7c5..c92faea1f8f 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -6,11 +6,9 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var d3 = require('d3'); -var Plotly = require('../plotly'); var Registry = require('../registry'); var Plots = require('../plots/plots'); var Lib = require('../lib'); @@ -19,6 +17,7 @@ var Color = require('../components/color'); var Drawing = require('../components/drawing'); var Titles = require('../components/titles'); var ModeBar = require('../components/modebar'); +var Axes = require('../plots/cartesian/axes'); var initInteractions = require('../plots/cartesian/graph_interact'); var cartesianConstants = require('../plots/cartesian/constants'); var alignmentConstants = require('../constants/alignment'); @@ -46,7 +45,7 @@ exports.lsInner = function(gd) { var fullLayout = gd._fullLayout; var gs = fullLayout._size; var pad = gs.p; - var axList = Plotly.Axes.list(gd); + var axList = Axes.list(gd); // _has('cartesian') means SVG specifically, not GL2D - but GL2D // can still get here because it makes some of the SVG structure @@ -339,7 +338,7 @@ exports.lsInner = function(gd) { plotinfo.ylines.attr('d', yPath); }); - Plotly.Axes.makeClipPaths(gd); + Axes.makeClipPaths(gd); exports.drawMainTitle(gd); ModeBar.manage(gd); @@ -462,7 +461,7 @@ exports.doColorBars = function(gd) { exports.layoutReplot = function(gd) { var layout = gd.layout; gd.layout = undefined; - return Plotly.plot(gd, '', layout); + return Registry.call('plot', gd, '', layout); }; exports.doLegend = function(gd) { @@ -471,7 +470,7 @@ exports.doLegend = function(gd) { }; exports.doTicksRelayout = function(gd) { - Plotly.Axes.doTicks(gd, 'redraw'); + Axes.doTicks(gd, 'redraw'); exports.drawMainTitle(gd); return Plots.previousPromises(gd); }; diff --git a/src/plot_api/to_image.js b/src/plot_api/to_image.js index 87b345c61d7..a06116b9194 100644 --- a/src/plot_api/to_image.js +++ b/src/plot_api/to_image.js @@ -8,7 +8,7 @@ 'use strict'; -var Plotly = require('../plotly'); +var plotApi = require('./plot_api'); var Lib = require('../lib'); var helpers = require('../snapshot/helpers'); @@ -155,7 +155,7 @@ function toImage(gd, opts) { var width = clonedGd._fullLayout.width; var height = clonedGd._fullLayout.height; - Plotly.purge(clonedGd); + plotApi.purge(clonedGd); document.body.removeChild(clonedGd); if(format === 'svg') { @@ -196,7 +196,7 @@ function toImage(gd, opts) { } return new Promise(function(resolve, reject) { - Plotly.plot(clonedGd, data, layoutImage, configImage) + plotApi.plot(clonedGd, data, layoutImage, configImage) .then(redrawFunc) .then(wait) .then(convert) diff --git a/src/plotly.js b/src/plotly.js deleted file mode 100644 index 9f52971c332..00000000000 --- a/src/plotly.js +++ /dev/null @@ -1,32 +0,0 @@ -/** -* Copyright 2012-2018, 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'; - -/* - * Pack internal modules unto an object. - * - * This object is require'ed in as 'Plotly' in numerous src and test files. - * Require'ing 'Plotly' bypasses circular dependencies. - * - * Future development should move away from this pattern. - * - */ - -// configuration -exports.defaultConfig = require('./plot_api/plot_config'); - -// plots -exports.Plots = require('./plots/plots'); -exports.Axes = require('./plots/cartesian/axes'); - -// components -exports.ModeBar = require('./components/modebar'); - -// plot api -require('./plot_api/plot_api'); diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index 90c32556a7b..6b36f98c82d 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -13,7 +13,6 @@ var d3 = require('d3'); var tinycolor = require('tinycolor2'); var supportsPassive = require('has-passive-events'); -var Plotly = require('../../plotly'); var Registry = require('../../registry'); var Lib = require('../../lib'); var svgTextUtils = require('../../lib/svg_text_utils'); @@ -213,7 +212,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { .on('edit', function(text) { var v = ax.d2r(text); if(v !== undefined) { - Plotly.relayout(gd, attrStr, v); + Registry.call('relayout', gd, attrStr, v); } }); } @@ -655,7 +654,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { } gd.emit('plotly_doubleclick', null); - Plotly.relayout(gd, attrs); + Registry.call('relayout', gd, attrs); } // dragTail - finish a drag event with a redraw @@ -669,7 +668,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { // accumulated MathJax promises - wait for them before we relayout. Lib.syncOrAsync([ Plots.previousPromises, - function() { Plotly.relayout(gd, updates); } + function() { Registry.call('relayout', gd, updates); } ], gd); } diff --git a/src/plots/cartesian/transition_axes.js b/src/plots/cartesian/transition_axes.js index a9b1b1f0166..281b9964b9b 100644 --- a/src/plots/cartesian/transition_axes.js +++ b/src/plots/cartesian/transition_axes.js @@ -6,12 +6,10 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var d3 = require('d3'); -var Plotly = require('../../plotly'); var Registry = require('../../registry'); var Drawing = require('../../components/drawing'); var Axes = require('./axes'); @@ -274,7 +272,7 @@ module.exports = function transitionAxes(gd, newLayout, transitionOpts, makeOnCo // Signal that this transition has completed: onComplete && onComplete(); - return Plotly.relayout(gd, aobj).then(function() { + return Registry.call('relayout', gd, aobj).then(function() { for(var i = 0; i < affectedSubplots.length; i++) { unsetSubplotTransform(affectedSubplots[i]); } @@ -291,7 +289,7 @@ module.exports = function transitionAxes(gd, newLayout, transitionOpts, makeOnCo axi.range = axi._r.slice(); } - return Plotly.relayout(gd, aobj).then(function() { + return Registry.call('relayout', gd, aobj).then(function() { for(var i = 0; i < affectedSubplots.length; i++) { unsetSubplotTransform(affectedSubplots[i]); } diff --git a/src/plots/command.js b/src/plots/command.js index dedb03c0fae..1a185cad43c 100644 --- a/src/plots/command.js +++ b/src/plots/command.js @@ -6,10 +6,9 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; -var Plotly = require('../plotly'); +var Registry = require('../registry'); var Lib = require('../lib'); /* @@ -264,17 +263,15 @@ function bindingValueHasChanged(gd, binding, cache) { exports.executeAPICommand = function(gd, method, args) { if(method === 'skip') return Promise.resolve(); - var apiMethod = Plotly[method]; - + var _method = Registry.apiMethodRegistry[method]; var allArgs = [gd]; - if(!Array.isArray(args)) args = []; for(var i = 0; i < args.length; i++) { allArgs.push(args[i]); } - return apiMethod.apply(null, allArgs).catch(function(err) { + return _method.apply(null, allArgs).catch(function(err) { Lib.warn('API call to Plotly.' + method + ' rejected.', err); return Promise.reject(err); }); diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js index 6aabf11a77f..f5ca806f1bb 100644 --- a/src/plots/geo/geo.js +++ b/src/plots/geo/geo.js @@ -12,7 +12,7 @@ var d3 = require('d3'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); @@ -208,7 +208,7 @@ proto.updateProjection = function(fullLayout, geoLayout) { this.viewInitial = null; Lib.warn(msg); - gd._promises.push(Plotly.relayout(gd, updateObj)); + gd._promises.push(Registry.call('relayout', gd, updateObj)); return msg; } @@ -365,7 +365,7 @@ proto.updateFx = function(fullLayout, geoLayout) { updateObj[_this.id + '.' + k] = viewInitial[k]; } - Plotly.relayout(gd, updateObj); + Registry.call('relayout', gd, updateObj); gd.emit('plotly_doubleclick', null); } diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 1e7e8e20bea..1dfee32e8f7 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -10,7 +10,6 @@ var fontAttrs = require('./font_attributes'); var colorAttrs = require('../components/color/attributes'); -var gridAttrs = require('./grid').attributes; var globalFont = fontAttrs({ editType: 'calc', @@ -196,6 +195,5 @@ module.exports = { 'being treated as immutable, thus any data array with a', 'different identity from its predecessor contains new data.' ].join(' ') - }, - grid: gridAttrs + } }; diff --git a/src/plots/plots.js b/src/plots/plots.js index db80e30dfed..bc91864c548 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -12,15 +12,13 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); -var Plotly = require('../plotly'); -var PlotSchema = require('../plot_api/plot_schema'); var Registry = require('../registry'); +var PlotSchema = require('../plot_api/plot_schema'); var axisIDs = require('../plots/cartesian/axis_ids'); var Lib = require('../lib'); var _ = Lib._; var Color = require('../components/color'); var BADNUM = require('../constants/numerical').BADNUM; -var Grid = require('./grid'); var plots = module.exports = {}; @@ -42,8 +40,6 @@ plots.fontWeight = 'normal'; var transformsRegistry = plots.transformsRegistry; -var ErrorBars = require('../components/errorbars'); - var commandModule = require('./command'); plots.executeAPICommand = commandModule.executeAPICommand; plots.computeAPICommandBindings = commandModule.computeAPICommandBindings; @@ -106,7 +102,7 @@ plots.resize = function(gd) { // nor should it be included in the undo queue gd.autoplay = true; - Plotly.relayout(gd, { autosize: true }).then(function() { + Registry.call('relayout', gd, {autosize: true}).then(function() { gd.changed = oldchanged; resolve(gd); }); @@ -1111,7 +1107,7 @@ plots.supplyTraceDefaults = function(traceIn, colorIndex, layout, traceInIndex) coerce('customdata'); coerce('ids'); - if(plots.traceIs(traceOut, 'showLegend')) { + if(Registry.traceIs(traceOut, 'showLegend')) { coerce('showlegend'); coerce('legendgroup'); } @@ -1128,9 +1124,9 @@ plots.supplyTraceDefaults = function(traceIn, colorIndex, layout, traceInIndex) Lib.coerceHoverinfo(traceIn, traceOut, layout); } - if(!plots.traceIs(traceOut, 'noOpacity')) coerce('opacity'); + if(!Registry.traceIs(traceOut, 'noOpacity')) coerce('opacity'); - if(plots.traceIs(traceOut, 'notLegendIsolatable')) { + if(Registry.traceIs(traceOut, 'notLegendIsolatable')) { // This clears out the legendonly state for traces like carpet that // cannot be isolated in the legend traceOut.visible = !!traceOut.visible; @@ -1251,7 +1247,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) { if(layoutIn.width && layoutIn.height) plots.sanitizeMargins(layoutOut); - Grid.sizeDefaults(layoutIn, layoutOut); + Registry.getComponentMethod('grid', 'sizeDefaults')(layoutIn, layoutOut); coerce('paper_bgcolor'); @@ -1390,7 +1386,7 @@ plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData, trans // ensure all cartesian axes have at least one subplot if(layoutOut._has('cartesian')) { - Grid.contentDefaults(layoutIn, layoutOut); + Registry.getComponentMethod('grid', 'contentDefaults')(layoutIn, layoutOut); Cartesian.finalizeSubplots(layoutIn, layoutOut); } @@ -1674,7 +1670,7 @@ plots.doAutoMargin = function(gd) { // if things changed and we're not already redrawing, trigger a redraw if(!fullLayout._replotting && oldmargins !== '{}' && oldmargins !== JSON.stringify(fullLayout._size)) { - return Plotly.plot(gd); + return Registry.call('plot', gd); } }; @@ -2118,7 +2114,7 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts) plots.doCalcdata(gd); - ErrorBars.calc(gd); + Registry.getComponentMethod('errorbars', 'calc')(gd); return Promise.resolve(); } @@ -2166,7 +2162,7 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts) if(frameOpts.redraw) { gd._transitionData._interruptCallbacks.push(function() { - return Plotly.redraw(gd); + return Registry.call('redraw', gd); }); } @@ -2238,7 +2234,7 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts) return Promise.resolve().then(function() { if(frameOpts.redraw) { - return Plotly.redraw(gd); + return Registry.call('redraw', gd); } }).then(function() { // Set transitioning false again once the redraw has occurred. This is used, for example, diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js index 7db125ce6bc..5f364aad176 100644 --- a/src/plots/polar/polar.js +++ b/src/plots/polar/polar.js @@ -11,7 +11,6 @@ var d3 = require('d3'); var tinycolor = require('tinycolor2'); -var Plotly = require('../../plotly'); var Registry = require('../../registry'); var Lib = require('../../lib'); var Color = require('../../components/color'); @@ -685,7 +684,7 @@ proto.updateMainDrag = function(fullLayout, polarLayout) { radialRange[0] + r1 * drange / radius ]; - Plotly.relayout(gd, updateObj); + Registry.call('relayout', gd, updateObj); } dragOpts.prepFn = function(evt, startX, startY) { @@ -719,7 +718,7 @@ proto.updateMainDrag = function(fullLayout, polarLayout) { } gd.emit('plotly_doubleclick', null); - Plotly.relayout(gd, updateObj); + Registry.call('relayout', gd, updateObj); } Fx.click(gd, evt, _this.id); @@ -789,9 +788,9 @@ proto.updateRadialDrag = function(fullLayout, polarLayout) { function doneFn() { if(angle1 !== null) { - Plotly.relayout(gd, _this.id + '.radialaxis.angle', angle1); + Registry.call('relayout', gd, _this.id + '.radialaxis.angle', angle1); } else if(rng1 !== null) { - Plotly.relayout(gd, _this.id + '.radialaxis.range[1]', rng1); + Registry.call('relayout', gd, _this.id + '.radialaxis.range[1]', rng1); } } @@ -971,7 +970,7 @@ proto.updateAngularDrag = function(fullLayout, polarLayout) { scatterTextPoints.select('text').attr('transform', null); var updateObj = {}; updateObj[_this.id + '.angularaxis.rotation'] = rot1; - Plotly.relayout(gd, updateObj); + Registry.call('relayout', gd, updateObj); } dragOpts.prepFn = function(evt, startX, startY) { diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 2b0f2ab0169..590e7c55316 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -12,7 +12,7 @@ var d3 = require('d3'); var tinycolor = require('tinycolor2'); -var Plotly = require('../../plotly'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var _ = Lib._; var Color = require('../../components/color'); @@ -27,7 +27,6 @@ var Titles = require('../../components/titles'); var prepSelect = require('../cartesian/select'); var constants = require('../cartesian/constants'); - function Ternary(options, fullLayout) { this.id = options.id; this.graphDiv = options.graphDiv; @@ -496,7 +495,7 @@ proto.initInteractions = function() { attrs[_this.id + '.baxis.min'] = 0; attrs[_this.id + '.caxis.min'] = 0; gd.emit('plotly_doubleclick', null); - Plotly.relayout(gd, attrs); + Registry.call('relayout', gd, attrs); } Fx.click(gd, evt, _this.id); } @@ -601,7 +600,7 @@ proto.initInteractions = function() { attrs[_this.id + '.baxis.min'] = mins.b; attrs[_this.id + '.caxis.min'] = mins.c; - Plotly.relayout(gd, attrs); + Registry.call('relayout', gd, attrs); if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) { Lib.notifier(_(gd, 'Double-click to zoom back out'), 'long'); @@ -680,7 +679,7 @@ proto.initInteractions = function() { attrs[_this.id + '.baxis.min'] = mins.b; attrs[_this.id + '.caxis.min'] = mins.c; - Plotly.relayout(gd, attrs); + Registry.call('relayout', gd, attrs); } function clearSelect() { diff --git a/src/registry.js b/src/registry.js index 53dc70fe74b..953e58b285e 100644 --- a/src/registry.js +++ b/src/registry.js @@ -6,19 +6,20 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Loggers = require('./lib/loggers'); var noop = require('./lib/noop'); var pushUnique = require('./lib/push_unique'); +var isPlainObject = require('./lib/is_plain_object'); var ExtendModule = require('./lib/extend'); -var extendFlat = ExtendModule.extendFlat; -var extendDeepAll = ExtendModule.extendDeepAll; var basePlotAttributes = require('./plots/attributes'); var baseLayoutAttributes = require('./plots/layout_attributes'); +var extendFlat = ExtendModule.extendFlat; +var extendDeepAll = ExtendModule.extendDeepAll; + exports.modules = {}; exports.allCategories = {}; exports.allTypes = []; @@ -29,175 +30,83 @@ exports.layoutArrayContainers = []; exports.layoutArrayRegexes = []; exports.traceLayoutAttributes = {}; exports.localeRegistry = {}; +exports.apiMethodRegistry = {}; /** - * register a module as the handler for a trace type + * Top-level register routine, exported as Plotly.register * - * @param {object} _module the module that will handle plotting this trace type - * @param {string} thisType - * @param {array of strings} categoriesIn all the categories this type is in, - * tested by calls: traceIs(trace, oneCategory) - * @param {object} meta meta information about the trace type - */ -exports.register = function(_module, thisType, categoriesIn, meta) { - if(exports.modules[thisType]) { - Loggers.log('Type ' + thisType + ' already registered'); - return; - } - - var categoryObj = {}; - for(var i = 0; i < categoriesIn.length; i++) { - categoryObj[categoriesIn[i]] = true; - exports.allCategories[categoriesIn[i]] = true; - } - - exports.modules[thisType] = { - _module: _module, - categories: categoryObj - }; - - if(meta && Object.keys(meta).length) { - exports.modules[thisType].meta = meta; - } - - exports.allTypes.push(thisType); - - for(var componentName in exports.componentsRegistry) { - mergeComponentAttrsToTrace(componentName, thisType); - } - - /* - * Collect all trace layout attributes in one place for easier lookup later - * but don't merge them into the base schema as it would confuse the docs - * (at least after https://github.com/plotly/documentation/issues/202 gets done!) - */ - if(_module.layoutAttributes) { - extendFlat(exports.traceLayoutAttributes, _module.layoutAttributes); - } -}; - -/** - * register a subplot type + * @param {object array or array of objects} _modules : + * module object or list of module object to register. + * + * A valid `moduleType: 'trace'` module has fields: + * - name {string} : the trace type + * - categories {array} : categories associated with this trace type, + * tested with Register.traceIs() + * - meta {object} : meta info (mostly for plot-schema) + * + * A valid `moduleType: 'locale'` module has fields: + * - name {string} : 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. + * - dictionary {object} : 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. + * - format {object} : a `d3.locale` format specifier for this locale + * any omitted keys we'll fall back on en-US. * - * @param {object} _module subplot module: + * A valid `moduleType: 'transform'` module has fields: + * - name {string} : transform name + * - transform {function} : default-level transform function + * - calcTransform {function} : calc-level transform function + * - attributes {object} : transform attributes declarations + * - supplyDefaults {function} : attributes default-supply function * - * @param {string or array of strings} attr - * attribute name in traces and layout - * @param {string or array of strings} idRoot - * root of id (setting the possible value for attrName) - * @param {object} attributes - * attribute(s) for traces of this subplot type + * A valid `moduleType: 'component'` module has fields: + * - name {string} : the component name, used it with Register.getComponentMethod() + * to employ component method. * - * In trace objects `attr` is the object key taking a valid `id` as value - * (the set of all valid ids is generated below and stored in idRegex). + * A valid `moduleType: 'apiMethod'` module has fields: + * - name {string} : the api method name. + * - fn {function} : the api method called with Register.call(); * - * In the layout object, a or several valid `attr` name(s) can be keys linked - * to a nested attribute objects - * (the set of all valid attr names is generated below and stored in attrRegex). */ -exports.registerSubplot = function(_module) { - var plotType = _module.name; - - if(exports.subplotsRegistry[plotType]) { - Loggers.log('Plot type ' + plotType + ' already registered.'); - return; - } - - // relayout array handling will look for component module methods with this - // name and won't find them because this is a subplot module... but that - // should be fine, it will just fall back on redrawing the plot. - findArrayRegexps(_module); - - // not sure what's best for the 'cartesian' type at this point - exports.subplotsRegistry[plotType] = _module; - - for(var componentName in exports.componentsRegistry) { - mergeComponentAttrsToSubplot(componentName, _module.name); +exports.register = function register(_modules) { + if(!_modules) { + throw new Error('No argument passed to Plotly.register.'); + } else if(_modules && !Array.isArray(_modules)) { + _modules = [_modules]; } -}; -exports.registerComponent = function(_module) { - var name = _module.name; - - exports.componentsRegistry[name] = _module; + for(var i = 0; i < _modules.length; i++) { + var newModule = _modules[i]; - if(_module.layoutAttributes) { - if(_module.layoutAttributes._isLinkedToArray) { - pushUnique(exports.layoutArrayContainers, name); + if(!newModule) { + throw new Error('Invalid module was attempted to be registered!'); } - findArrayRegexps(_module); - } - - for(var traceType in exports.modules) { - mergeComponentAttrsToTrace(name, traceType); - } - for(var subplotName in exports.subplotsRegistry) { - mergeComponentAttrsToSubplot(name, subplotName); - } - - for(var transformType in exports.transformsRegistry) { - mergeComponentAttrsToTransform(name, transformType); - } - - if(_module.schema && _module.schema.layout) { - extendDeepAll(baseLayoutAttributes, _module.schema.layout); - } -}; - -exports.registerTransform = function(_module) { - exports.transformsRegistry[_module.name] = _module; - - for(var componentName in exports.componentsRegistry) { - mergeComponentAttrsToTransform(componentName, _module.name); - } -}; - -function findArrayRegexps(_module) { - if(_module.layoutAttributes) { - var arrayAttrRegexps = _module.layoutAttributes._arrayAttrRegexps; - if(arrayAttrRegexps) { - for(var i = 0; i < arrayAttrRegexps.length; i++) { - pushUnique(exports.layoutArrayRegexes, arrayAttrRegexps[i]); - } + switch(newModule.moduleType) { + case 'trace': + registerTraceModule(newModule); + break; + case 'transform': + registerTransformModule(newModule); + break; + case 'component': + registerComponentModule(newModule); + break; + case 'locale': + registerLocale(newModule); + break; + case 'apiMethod': + var name = newModule.name; + exports.apiMethodRegistry[name] = newModule.fn; + break; + default: + throw new Error('Invalid module was attempted to be registered!'); } } -} - -function mergeComponentAttrsToTrace(componentName, traceType) { - var componentSchema = exports.componentsRegistry[componentName].schema; - if(!componentSchema || !componentSchema.traces) return; - - var traceAttrs = componentSchema.traces[traceType]; - if(traceAttrs) { - extendDeepAll(exports.modules[traceType]._module.attributes, traceAttrs); - } -} - -function mergeComponentAttrsToTransform(componentName, transformType) { - var componentSchema = exports.componentsRegistry[componentName].schema; - if(!componentSchema || !componentSchema.transforms) return; - - var transformAttrs = componentSchema.transforms[transformType]; - if(transformAttrs) { - extendDeepAll(exports.transformsRegistry[transformType].attributes, transformAttrs); - } -} - -function mergeComponentAttrsToSubplot(componentName, subplotName) { - var componentSchema = exports.componentsRegistry[componentName].schema; - if(!componentSchema || !componentSchema.subplots) return; - - var subplotModule = exports.subplotsRegistry[subplotName]; - var subplotAttrs = subplotModule.layoutAttributes; - var subplotAttr = subplotModule.attr === 'subplot' ? subplotModule.name : subplotModule.attr; - if(Array.isArray(subplotAttr)) subplotAttr = subplotAttr[0]; - - var componentLayoutAttrs = componentSchema.subplots[subplotAttr]; - if(subplotAttrs && componentLayoutAttrs) { - extendDeepAll(subplotAttrs, componentLayoutAttrs); - } -} +}; /** * Get registered module using trace object or trace type @@ -280,7 +189,6 @@ exports.hasTransform = function(data, type) { } } return false; - }; /** @@ -300,31 +208,151 @@ exports.getComponentMethod = function(name, method) { return _module[method] || noop; }; -function getTraceType(traceType) { - if(typeof traceType === 'object') traceType = traceType.type; - return traceType; -} - /** - * Register a new locale dictionary + * Call registered api method. * - * @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. - * @param {object} module.format - * a `d3.locale` format specifier for this locale - * any omitted keys we'll fall back on en-US + * @param {string} name : api method name + * @param {...array} args : arguments passed to api method + * @return {any} : returns api method output */ -exports.registerLocale = function(_module) { +exports.call = function() { + var name = arguments[0]; + var args = [].slice.call(arguments, 1); + return exports.apiMethodRegistry[name].apply(null, args); +}; + +function registerTraceModule(_module) { + var thisType = _module.name; + var categoriesIn = _module.categories; + var meta = _module.meta; + + if(exports.modules[thisType]) { + Loggers.log('Type ' + thisType + ' already registered'); + return; + } + + if(!exports.subplotsRegistry[_module.basePlotModule.name]) { + registerSubplot(_module.basePlotModule); + } + + var categoryObj = {}; + for(var i = 0; i < categoriesIn.length; i++) { + categoryObj[categoriesIn[i]] = true; + exports.allCategories[categoriesIn[i]] = true; + } + + exports.modules[thisType] = { + _module: _module, + categories: categoryObj + }; + + if(meta && Object.keys(meta).length) { + exports.modules[thisType].meta = meta; + } + + exports.allTypes.push(thisType); + + for(var componentName in exports.componentsRegistry) { + mergeComponentAttrsToTrace(componentName, thisType); + } + + /* + * Collect all trace layout attributes in one place for easier lookup later + * but don't merge them into the base schema as it would confuse the docs + * (at least after https://github.com/plotly/documentation/issues/202 gets done!) + */ + if(_module.layoutAttributes) { + extendFlat(exports.traceLayoutAttributes, _module.layoutAttributes); + } +} + +function registerSubplot(_module) { + var plotType = _module.name; + + if(exports.subplotsRegistry[plotType]) { + Loggers.log('Plot type ' + plotType + ' already registered.'); + return; + } + + // relayout array handling will look for component module methods with this + // name and won't find them because this is a subplot module... but that + // should be fine, it will just fall back on redrawing the plot. + findArrayRegexps(_module); + + // not sure what's best for the 'cartesian' type at this point + exports.subplotsRegistry[plotType] = _module; + + for(var componentName in exports.componentsRegistry) { + mergeComponentAttrsToSubplot(componentName, _module.name); + } +} + +function registerComponentModule(_module) { + if(typeof _module.name !== 'string') { + throw new Error('Component module *name* must be a string.'); + } + + var name = _module.name; + exports.componentsRegistry[name] = _module; + + if(_module.layoutAttributes) { + if(_module.layoutAttributes._isLinkedToArray) { + pushUnique(exports.layoutArrayContainers, name); + } + findArrayRegexps(_module); + } + + for(var traceType in exports.modules) { + mergeComponentAttrsToTrace(name, traceType); + } + + for(var subplotName in exports.subplotsRegistry) { + mergeComponentAttrsToSubplot(name, subplotName); + } + + for(var transformType in exports.transformsRegistry) { + mergeComponentAttrsToTransform(name, transformType); + } + + if(_module.schema && _module.schema.layout) { + extendDeepAll(baseLayoutAttributes, _module.schema.layout); + } +} + +function registerTransformModule(_module) { + if(typeof _module.name !== 'string') { + throw new Error('Transform module *name* must be a string.'); + } + + var prefix = 'Transform module ' + _module.name; + var hasTransform = typeof _module.transform === 'function'; + var hasCalcTransform = typeof _module.calcTransform === 'function'; + + if(!hasTransform && !hasCalcTransform) { + throw new Error(prefix + ' is missing a *transform* or *calcTransform* method.'); + } + if(hasTransform && hasCalcTransform) { + Loggers.log([ + prefix + ' has both a *transform* and *calcTransform* methods.', + 'Please note that all *transform* methods are executed', + 'before all *calcTransform* methods.' + ].join(' ')); + } + if(!isPlainObject(_module.attributes)) { + Loggers.log(prefix + ' registered without an *attributes* object.'); + } + if(typeof _module.supplyDefaults !== 'function') { + Loggers.log(prefix + ' registered without a *supplyDefaults* method.'); + } + + exports.transformsRegistry[_module.name] = _module; + + for(var componentName in exports.componentsRegistry) { + mergeComponentAttrsToTransform(componentName, _module.name); + } +} + +function registerLocale(_module) { var locale = _module.name; var baseLocale = locale.split('-')[0]; @@ -358,4 +386,55 @@ exports.registerLocale = function(_module) { if(hasDict) localeObj.dictionary = newDict; if(hasFormat) localeObj.format = newFormat; -}; +} + +function findArrayRegexps(_module) { + if(_module.layoutAttributes) { + var arrayAttrRegexps = _module.layoutAttributes._arrayAttrRegexps; + if(arrayAttrRegexps) { + for(var i = 0; i < arrayAttrRegexps.length; i++) { + pushUnique(exports.layoutArrayRegexes, arrayAttrRegexps[i]); + } + } + } +} + +function mergeComponentAttrsToTrace(componentName, traceType) { + var componentSchema = exports.componentsRegistry[componentName].schema; + if(!componentSchema || !componentSchema.traces) return; + + var traceAttrs = componentSchema.traces[traceType]; + if(traceAttrs) { + extendDeepAll(exports.modules[traceType]._module.attributes, traceAttrs); + } +} + +function mergeComponentAttrsToTransform(componentName, transformType) { + var componentSchema = exports.componentsRegistry[componentName].schema; + if(!componentSchema || !componentSchema.transforms) return; + + var transformAttrs = componentSchema.transforms[transformType]; + if(transformAttrs) { + extendDeepAll(exports.transformsRegistry[transformType].attributes, transformAttrs); + } +} + +function mergeComponentAttrsToSubplot(componentName, subplotName) { + var componentSchema = exports.componentsRegistry[componentName].schema; + if(!componentSchema || !componentSchema.subplots) return; + + var subplotModule = exports.subplotsRegistry[subplotName]; + var subplotAttrs = subplotModule.layoutAttributes; + var subplotAttr = subplotModule.attr === 'subplot' ? subplotModule.name : subplotModule.attr; + if(Array.isArray(subplotAttr)) subplotAttr = subplotAttr[0]; + + var componentLayoutAttrs = componentSchema.subplots[subplotAttr]; + if(subplotAttrs && componentLayoutAttrs) { + extendDeepAll(subplotAttrs, componentLayoutAttrs); + } +} + +function getTraceType(traceType) { + if(typeof traceType === 'object') traceType = traceType.type; + return traceType; +} diff --git a/src/snapshot/toimage.js b/src/snapshot/toimage.js index dbaebb9b67e..6fd3c03acc5 100644 --- a/src/snapshot/toimage.js +++ b/src/snapshot/toimage.js @@ -10,7 +10,7 @@ var EventEmitter = require('events').EventEmitter; -var Plotly = require('../plotly'); +var Registry = require('../registry'); var Lib = require('../lib'); var helpers = require('./helpers'); @@ -18,7 +18,6 @@ var clonePlot = require('./cloneplot'); var toSVG = require('./tosvg'); var svgToImg = require('./svgtoimg'); - /** * @param {object} gd figure Object * @param {object} opts option object @@ -64,7 +63,7 @@ function toImage(gd, opts) { var redrawFunc = helpers.getRedrawFunc(clonedGd); - Plotly.plot(clonedGd, clone.data, clone.layout, clone.config) + Registry.call('plot', clonedGd, clone.data, clone.layout, clone.config) .then(redrawFunc) .then(wait) .catch(function(err) { diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js index 0d3d131224e..de806adb46b 100644 --- a/src/traces/bar/attributes.js +++ b/src/traces/bar/attributes.js @@ -10,7 +10,6 @@ var scatterAttrs = require('../scatter/attributes'); var colorAttributes = require('../../components/colorscale/color_attributes'); -var errorBarAttrs = require('../../components/errorbars/attributes'); var colorbarAttrs = require('../../components/colorbar/attributes'); var fontAttrs = require('../../plots/font_attributes'); @@ -190,9 +189,6 @@ module.exports = { r: scatterAttrs.r, t: scatterAttrs.t, - error_y: errorBarAttrs, - error_x: errorBarAttrs, - _deprecated: { bardir: { valType: 'enumerated', diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js index 04096b33ff4..02a2846737d 100644 --- a/src/traces/bar/defaults.js +++ b/src/traces/bar/defaults.js @@ -11,10 +11,10 @@ var Lib = require('../../lib'); var Color = require('../../components/color'); +var Registry = require('../../registry'); var handleXYDefaults = require('../scatter/xy_defaults'); var handleStyleDefaults = require('../bar/style_defaults'); -var errorBarsSupplyDefaults = require('../../components/errorbars/defaults'); var attributes = require('./attributes'); module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { @@ -57,6 +57,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout); // override defaultColor for error bars with defaultLine + var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults'); errorBarsSupplyDefaults(traceIn, traceOut, Color.defaultLine, {axis: 'y'}); errorBarsSupplyDefaults(traceIn, traceOut, Color.defaultLine, {axis: 'x', inherit: 'y'}); diff --git a/src/traces/bar/hover.js b/src/traces/bar/hover.js index 6eaa9c439eb..933b4401232 100644 --- a/src/traces/bar/hover.js +++ b/src/traces/bar/hover.js @@ -10,7 +10,7 @@ 'use strict'; var Fx = require('../../components/fx'); -var ErrorBars = require('../../components/errorbars'); +var Registry = require('../../registry'); var Color = require('../../components/color'); var fillHoverText = require('../scatter/fill_hover_text'); @@ -140,7 +140,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { pointData[posLetter + 'Spike'] = pa.c2p(di.p, true); fillHoverText(di, trace, pointData); - ErrorBars.hoverInfo(di, trace, pointData); + Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData); return [pointData]; }; diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index c18d036c0d0..30914fecb14 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -18,7 +18,7 @@ var svgTextUtils = require('../../lib/svg_text_utils'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); -var ErrorBars = require('../../components/errorbars'); +var Registry = require('../../registry'); var attributes = require('./attributes'), attributeText = attributes.text, @@ -150,7 +150,7 @@ module.exports = function plot(gd, plotinfo, cdbar) { }); // error bars are on the top - bartraces.call(ErrorBars.plot, plotinfo); + Registry.getComponentMethod('errorbars', 'plot')(bartraces, plotinfo); // lastly, clip points groups of `cliponaxis !== false` traces // on `plotinfo._hasClipOnAxisFalse === true` subplots diff --git a/src/traces/bar/style.js b/src/traces/bar/style.js index 455f04bc73f..8dbb15b249c 100644 --- a/src/traces/bar/style.js +++ b/src/traces/bar/style.js @@ -11,7 +11,7 @@ var d3 = require('d3'); var Drawing = require('../../components/drawing'); -var ErrorBars = require('../../components/errorbars'); +var Registry = require('../../registry'); module.exports = function style(gd, cd) { var s = cd ? cd[0].node3 : d3.select(gd).selectAll('g.trace.bars'); @@ -64,5 +64,5 @@ module.exports = function style(gd, cd) { Drawing.selectedTextStyle(txs, trace); }); - ErrorBars.style(s); + Registry.getComponentMethod('errorbars', 'style')(s); }; diff --git a/src/traces/candlestick/index.js b/src/traces/candlestick/index.js index cd206cd77ad..dff5c003935 100644 --- a/src/traces/candlestick/index.js +++ b/src/traces/candlestick/index.js @@ -6,10 +6,9 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; -var register = require('../../plot_api/register'); +var Registry = require('../../registry'); module.exports = { moduleType: 'trace', @@ -36,5 +35,5 @@ module.exports = { supplyDefaults: require('./defaults'), }; -register(require('../box')); -register(require('./transform')); +Registry.register(require('../box')); +Registry.register(require('./transform')); diff --git a/src/traces/histogram/attributes.js b/src/traces/histogram/attributes.js index 30f41355980..f15e85b6fc2 100644 --- a/src/traces/histogram/attributes.js +++ b/src/traces/histogram/attributes.js @@ -10,7 +10,6 @@ var barAttrs = require('../bar/attributes'); - module.exports = { x: { valType: 'data_array', @@ -194,9 +193,6 @@ module.exports = { selected: barAttrs.selected, unselected: barAttrs.unselected, - error_y: barAttrs.error_y, - error_x: barAttrs.error_x, - _deprecated: { bardir: barAttrs._deprecated.bardir } diff --git a/src/traces/histogram/defaults.js b/src/traces/histogram/defaults.js index 7e603357524..79b3dcb9985 100644 --- a/src/traces/histogram/defaults.js +++ b/src/traces/histogram/defaults.js @@ -15,7 +15,6 @@ var Color = require('../../components/color'); var handleBinDefaults = require('./bin_defaults'); var handleStyleDefaults = require('../bar/style_defaults'); -var errorBarsSupplyDefaults = require('../../components/errorbars/defaults'); var attributes = require('./attributes'); module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { @@ -54,6 +53,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout); // override defaultColor for error bars with defaultLine + var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults'); errorBarsSupplyDefaults(traceIn, traceOut, Color.defaultLine, {axis: 'y'}); errorBarsSupplyDefaults(traceIn, traceOut, Color.defaultLine, {axis: 'x', inherit: 'y'}); diff --git a/src/traces/ohlc/index.js b/src/traces/ohlc/index.js index 4350cc2c653..d8d2f12f650 100644 --- a/src/traces/ohlc/index.js +++ b/src/traces/ohlc/index.js @@ -6,10 +6,9 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; -var register = require('../../plot_api/register'); +var Registry = require('../../registry'); module.exports = { moduleType: 'trace', @@ -36,5 +35,5 @@ module.exports = { supplyDefaults: require('./defaults'), }; -register(require('../scatter')); -register(require('./transform')); +Registry.register(require('../scatter')); +Registry.register(require('./transform')); diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index e132100b5af..561604aee6e 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -9,7 +9,6 @@ 'use strict'; var colorAttributes = require('../../components/colorscale/color_attributes'); -var errorBarAttrs = require('../../components/errorbars/attributes'); var colorbarAttrs = require('../../components/colorbar/attributes'); var fontAttrs = require('../../plots/font_attributes'); var dash = require('../../components/drawing/attributes').dash; @@ -490,8 +489,5 @@ module.exports = { 'Please switch to *scatterpolar* trace type.', 'Sets the angular coordinates.' ].join('') - }, - - error_y: errorBarAttrs, - error_x: errorBarAttrs + } }; diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js index 6f3cc0cbf69..ba9fa7c5c2c 100644 --- a/src/traces/scatter/defaults.js +++ b/src/traces/scatter/defaults.js @@ -6,10 +6,10 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Lib = require('../../lib'); +var Registry = require('../../registry'); var attributes = require('./attributes'); var constants = require('./constants'); @@ -20,7 +20,6 @@ var handleLineDefaults = require('./line_defaults'); var handleLineShapeDefaults = require('./line_shape_defaults'); var handleTextDefaults = require('./text_defaults'); var handleFillColorDefaults = require('./fillcolor_defaults'); -var errorBarsSupplyDefaults = require('../../components/errorbars/defaults'); module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { @@ -73,6 +72,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('hoveron', dfltHoverOn.join('+') || 'points'); + var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults'); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'y'}); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'x', inherit: 'y'}); diff --git a/src/traces/scatter/hover.js b/src/traces/scatter/hover.js index 8ab0dac0f4b..f85a1a77094 100644 --- a/src/traces/scatter/hover.js +++ b/src/traces/scatter/hover.js @@ -10,7 +10,7 @@ var Lib = require('../../lib'); var Fx = require('../../components/fx'); -var ErrorBars = require('../../components/errorbars'); +var Registry = require('../../registry'); var getTraceColor = require('./get_trace_color'); var Color = require('../../components/color'); var fillHoverText = require('./fill_hover_text'); @@ -83,7 +83,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { }); fillHoverText(di, trace, pointData); - ErrorBars.hoverInfo(di, trace, pointData); + Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData); return [pointData]; } diff --git a/src/traces/scatter/plot.js b/src/traces/scatter/plot.js index 6d17026691b..db0456edf8a 100644 --- a/src/traces/scatter/plot.js +++ b/src/traces/scatter/plot.js @@ -11,9 +11,9 @@ var d3 = require('d3'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var Drawing = require('../../components/drawing'); -var ErrorBars = require('../../components/errorbars'); var subTypes = require('./subtypes'); var linePoints = require('./line_points'); @@ -164,9 +164,8 @@ function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transition line = trace.line, tr = d3.select(element); - // (so error bars can find them along with bars) // error bars are at the bottom - tr.call(ErrorBars.plot, plotinfo, transitionOpts); + Registry.getComponentMethod('errorbars', 'plot')(tr, plotinfo, transitionOpts); if(trace.visible !== true) return; diff --git a/src/traces/scatter/style.js b/src/traces/scatter/style.js index 33e2cfc8967..67becae9b91 100644 --- a/src/traces/scatter/style.js +++ b/src/traces/scatter/style.js @@ -11,7 +11,7 @@ var d3 = require('d3'); var Drawing = require('../../components/drawing'); -var ErrorBars = require('../../components/errorbars'); +var Registry = require('../../registry'); function style(gd, cd) { var s = cd ? cd[0].node3 : d3.select(gd).selectAll('g.trace.scatter'); @@ -32,7 +32,7 @@ function style(gd, cd) { s.selectAll('g.trace path.js-fill') .call(Drawing.fillGroupStyle); - s.call(ErrorBars.style); + Registry.getComponentMethod('errorbars', 'style')(s); } function stylePoints(sel, trace, gd) { diff --git a/src/traces/scatter3d/attributes.js b/src/traces/scatter3d/attributes.js index 1f814195485..3cc32486bdc 100644 --- a/src/traces/scatter3d/attributes.js +++ b/src/traces/scatter3d/attributes.js @@ -10,7 +10,6 @@ var scatterAttrs = require('../scatter/attributes'); var colorAttributes = require('../../components/colorscale/color_attributes'); -var errorBarAttrs = require('../../components/errorbars/attributes'); var baseAttrs = require('../../plots/attributes'); var DASHES = require('../../constants/gl3d_dashes'); @@ -169,10 +168,6 @@ var attrs = module.exports = overrideAll({ textposition: extendFlat({}, scatterAttrs.textposition, {dflt: 'top center'}), textfont: scatterAttrs.textfont, - error_x: errorBarAttrs, - error_y: errorBarAttrs, - error_z: errorBarAttrs, - hoverinfo: extendFlat({}, baseAttrs.hoverinfo) }, 'calc', 'nested'); diff --git a/src/traces/scatter3d/calc_errors.js b/src/traces/scatter3d/calc_errors.js index 4267fc37096..ecc1f8ee87d 100644 --- a/src/traces/scatter3d/calc_errors.js +++ b/src/traces/scatter3d/calc_errors.js @@ -11,7 +11,6 @@ var makeComputeError = require('../../components/errorbars/compute_error'); - function calculateAxisErrors(data, params, scaleFactor) { if(!params || !params.visible) return null; diff --git a/src/traces/scatter3d/defaults.js b/src/traces/scatter3d/defaults.js index 050a2dcfed3..afbad02ecea 100644 --- a/src/traces/scatter3d/defaults.js +++ b/src/traces/scatter3d/defaults.js @@ -16,11 +16,9 @@ var subTypes = require('../scatter/subtypes'); var handleMarkerDefaults = require('../scatter/marker_defaults'); var handleLineDefaults = require('../scatter/line_defaults'); var handleTextDefaults = require('../scatter/text_defaults'); -var errorBarsSupplyDefaults = require('../../components/errorbars/defaults'); var attributes = require('./attributes'); - module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { @@ -63,6 +61,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } } + var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults'); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'z'}); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'y', inherit: 'z'}); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'x', inherit: 'z'}); diff --git a/src/traces/scattergl/attributes.js b/src/traces/scattergl/attributes.js index f358c70af0c..e0d469b6ddf 100644 --- a/src/traces/scattergl/attributes.js +++ b/src/traces/scattergl/attributes.js @@ -87,8 +87,6 @@ var attrs = module.exports = overrideAll({ editType: 'calc' }), - error_y: scatterAttrs.error_y, - error_x: scatterAttrs.error_x }, 'calc', 'nested'); attrs.x.editType = attrs.y.editType = attrs.x0.editType = attrs.y0.editType = 'calc+clearAxisTypes'; diff --git a/src/traces/scattergl/defaults.js b/src/traces/scattergl/defaults.js index 24b1281b129..1f55a192881 100644 --- a/src/traces/scattergl/defaults.js +++ b/src/traces/scattergl/defaults.js @@ -6,21 +6,18 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Lib = require('../../lib'); +var Registry = require('../../registry'); +var attributes = require('./attributes'); var constants = require('../scatter/constants'); var subTypes = require('../scatter/subtypes'); var handleXYDefaults = require('../scatter/xy_defaults'); var handleMarkerDefaults = require('../scatter/marker_defaults'); var handleLineDefaults = require('../scatter/line_defaults'); var handleFillColorDefaults = require('../scatter/fillcolor_defaults'); -var errorBarsSupplyDefaults = require('../../components/errorbars/defaults'); - -var attributes = require('./attributes'); - module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { @@ -63,6 +60,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('hoveron', dfltHoverOn.join('+') || 'points'); + var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults'); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'y'}); errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'x', inherit: 'y'}); diff --git a/src/traces/scattergl/index.js b/src/traces/scattergl/index.js index 80af61197b3..208495ba8f6 100644 --- a/src/traces/scattergl/index.js +++ b/src/traces/scattergl/index.js @@ -17,10 +17,10 @@ var rgba = require('color-normalize'); var svgSdf = require('svg-path-sdf'); var arrayRange = require('array-range'); +var Registry = require('../../registry'); var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); var Drawing = require('../../components/drawing'); -var ErrorBars = require('../../components/errorbars'); var formatColor = require('../../lib/gl_format_color'); var subTypes = require('../scatter/subtypes'); @@ -194,7 +194,9 @@ function sceneOptions(gd, subplot, trace, positions) { var linePositions; // get error values - var errorVals = hasError ? ErrorBars.calcFromTrace(trace, fullLayout) : null; + var errorVals = hasError ? + Registry.getComponentMethod('errorbars', 'calcFromTrace')(trace, fullLayout) : + null; if(hasErrorX) { errorXOptions = {}; @@ -1129,7 +1131,7 @@ function hoverPoints(pointData, xval, yval, hovermode) { else if(trace.text) pointData.text = trace.text; fillHoverText(di, trace, pointData); - ErrorBars.hoverInfo(di, trace, pointData); + Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData); return [pointData]; } diff --git a/tasks/test_syntax.js b/tasks/test_syntax.js index 2262d4ff095..1b61286f14b 100644 --- a/tasks/test_syntax.js +++ b/tasks/test_syntax.js @@ -260,12 +260,9 @@ function assertCircularDeps() { var circularDeps = res.circular(); var logs = []; - // see https://github.com/plotly/plotly.js/milestone/9 - var MAX_ALLOWED_CIRCULAR_DEPS = 16; - - if(circularDeps.length > MAX_ALLOWED_CIRCULAR_DEPS) { + if(circularDeps.length) { console.log(circularDeps.join('\n')); - logs.push('some new circular dependencies were added to src/'); + logs.push('some circular dependencies were found in src/'); } log('circular dependencies: ' + circularDeps.length, logs); diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index b39f0575bfc..79101a8649f 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -260,9 +260,7 @@ if(isFullSuite) { } } else { // Add lib/index.js to non-full-suite runs, - // to avoid import conflicts due to plotly.js - // circular dependencies. - + // to make sure the registry is set-up correctly. func.defaultConfig.files.push( pathToJQuery, pathToMain diff --git a/test/jasmine/tests/command_test.js b/test/jasmine/tests/command_test.js index ba061fefb3d..fe02f8812ca 100644 --- a/test/jasmine/tests/command_test.js +++ b/test/jasmine/tests/command_test.js @@ -1,5 +1,5 @@ var Plotly = require('@lib/index'); -var PlotlyInternal = require('@src/plotly'); +var Registry = require('@src/registry'); var Plots = Plotly.Plots; var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); @@ -21,14 +21,14 @@ describe('Plots.executeAPICommand', function() { describe('with a successful API command', function() { beforeEach(function() { - spyOn(PlotlyInternal, 'restyle').and.callFake(function() { + spyOn(Registry.apiMethodRegistry, 'restyle').and.callFake(function() { return Promise.resolve('resolution'); }); }); it('calls the API method and resolves', function(done) { Plots.executeAPICommand(gd, 'restyle', ['foo', 'bar']).then(function(value) { - var m = PlotlyInternal.restyle; + var m = Registry.apiMethodRegistry.restyle; expect(m).toHaveBeenCalled(); expect(m.calls.count()).toEqual(1); expect(m.calls.argsFor(0)).toEqual([gd, 'foo', 'bar']); @@ -41,14 +41,14 @@ describe('Plots.executeAPICommand', function() { describe('with an unsuccessful command', function() { beforeEach(function() { - spyOn(PlotlyInternal, 'restyle').and.callFake(function() { + spyOn(Registry.apiMethodRegistry, 'restyle').and.callFake(function() { return Promise.reject('rejection'); }); }); it('calls the API method and rejects', function(done) { Plots.executeAPICommand(gd, 'restyle', ['foo', 'bar']).then(fail, function(value) { - var m = PlotlyInternal.restyle; + var m = Registry.apiMethodRegistry.restyle; expect(m).toHaveBeenCalled(); expect(m.calls.count()).toEqual(1); expect(m.calls.argsFor(0)).toEqual([gd, 'foo', 'bar']); diff --git a/test/jasmine/tests/gl2d_plot_interact_test.js b/test/jasmine/tests/gl2d_plot_interact_test.js index 7ebdd5c2756..ffcda67b908 100644 --- a/test/jasmine/tests/gl2d_plot_interact_test.js +++ b/test/jasmine/tests/gl2d_plot_interact_test.js @@ -348,7 +348,7 @@ describe('@gl Test gl2d plots', function() { .then(done); }); - it('should be able to toggle visibility', function(done) { + it('@flaky should be able to toggle visibility', function(done) { var _mock = Lib.extendDeep({}, mock); _mock.data[0].line.width = 5; diff --git a/test/jasmine/tests/lib_test.js b/test/jasmine/tests/lib_test.js index d167d8feadb..71310d12b55 100644 --- a/test/jasmine/tests/lib_test.js +++ b/test/jasmine/tests/lib_test.js @@ -5,10 +5,9 @@ var config = require('@src/plot_api/plot_config'); var d3 = require('d3'); var Plotly = require('@lib'); -var PlotlyInternal = require('@src/plotly'); +var Plots = require('@src/plots/plots'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); -var Plots = PlotlyInternal.Plots; var failTest = require('../assets/fail_test'); describe('Test lib.js:', function() { diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 0dfebad8e73..6f65a6ce049 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -1,5 +1,5 @@ var Plotly = require('@lib/index'); -var PlotlyInternal = require('@src/plotly'); +var plotApi = require('@src/plot_api/plot_api'); var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var Queue = require('@src/lib/queue'); @@ -569,7 +569,7 @@ describe('Test plot api', function() { describe('Plotly.restyle subroutines switchboard', function() { beforeEach(function() { - spyOn(PlotlyInternal, 'plot'); + spyOn(plotApi, 'plot'); spyOn(Plots, 'previousPromises'); spyOn(Scatter, 'arraysToCalcdata'); spyOn(Bar, 'arraysToCalcdata'); @@ -594,7 +594,7 @@ describe('Test plot api', function() { expect(Scatter.arraysToCalcdata).toHaveBeenCalled(); expect(Bar.arraysToCalcdata).not.toHaveBeenCalled(); expect(Plots.style).toHaveBeenCalled(); - expect(PlotlyInternal.plot).not.toHaveBeenCalled(); + expect(plotApi.plot).not.toHaveBeenCalled(); // "docalc" deletes gd.calcdata - make sure this didn't happen expect(gd.calcdata).toBeDefined(); }); @@ -609,7 +609,7 @@ describe('Test plot api', function() { expect(Scatter.arraysToCalcdata).not.toHaveBeenCalled(); expect(Bar.arraysToCalcdata).toHaveBeenCalled(); expect(Plots.style).toHaveBeenCalled(); - expect(PlotlyInternal.plot).not.toHaveBeenCalled(); + expect(plotApi.plot).not.toHaveBeenCalled(); expect(gd.calcdata).toBeDefined(); }); @@ -622,25 +622,25 @@ describe('Test plot api', function() { mockDefaultsAndCalc(gd); Plotly.restyle(gd, 'marker.color', [['red', 'green', 'blue']]); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'marker.color', 'yellow'); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'marker.color', 'blue'); expect(gd.calcdata).toBeDefined(); - expect(PlotlyInternal.plot).not.toHaveBeenCalled(); + expect(plotApi.plot).not.toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'marker.color', [['red', 'blue', 'green']]); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); }); it('should do full replot when arrayOk base attributes are updated', function() { @@ -652,25 +652,25 @@ describe('Test plot api', function() { mockDefaultsAndCalc(gd); Plotly.restyle(gd, 'hoverlabel.bgcolor', [['red', 'green', 'blue']]); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'hoverlabel.bgcolor', 'yellow'); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'hoverlabel.bgcolor', 'blue'); expect(gd.calcdata).toBeDefined(); - expect(PlotlyInternal.plot).not.toHaveBeenCalled(); + expect(plotApi.plot).not.toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'hoverlabel.bgcolor', [['red', 'blue', 'green']]); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); }); it('should do full replot when attribute container are updated', function() { @@ -689,7 +689,7 @@ describe('Test plot api', function() { } }); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); }); it('calls plot on xgap and ygap styling', function() { @@ -700,10 +700,10 @@ describe('Test plot api', function() { mockDefaultsAndCalc(gd); Plotly.restyle(gd, {'xgap': 2}); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); Plotly.restyle(gd, {'ygap': 2}); - expect(PlotlyInternal.plot.calls.count()).toEqual(2); + expect(plotApi.plot.calls.count()).toEqual(2); }); it('should clear calcdata when restyling \'zmin\' and \'zmax\' on contour traces', function() { @@ -726,16 +726,16 @@ describe('Test plot api', function() { mocks.forEach(function(gd) { mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'zmin', 0); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'zmax', 10); expect(gd.calcdata).toBeUndefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); }); }); @@ -759,16 +759,16 @@ describe('Test plot api', function() { mocks.forEach(function(gd) { mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'zmin', 0); expect(gd.calcdata).toBeDefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); mockDefaultsAndCalc(gd); - PlotlyInternal.plot.calls.reset(); + plotApi.plot.calls.reset(); Plotly.restyle(gd, 'zmax', 10); expect(gd.calcdata).toBeDefined(); - expect(PlotlyInternal.plot).toHaveBeenCalled(); + expect(plotApi.plot).toHaveBeenCalled(); }); }); @@ -1227,7 +1227,7 @@ describe('Test plot api', function() { {'name': 'd'} ] }; - spyOn(PlotlyInternal, 'redraw'); + spyOn(plotApi, 'redraw'); }); it('should throw an error when indices are omitted', function() { @@ -1263,7 +1263,7 @@ describe('Test plot api', function() { Plotly.deleteTraces(gd, -1); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1275,7 +1275,7 @@ describe('Test plot api', function() { Plotly.deleteTraces(gd, [0, 3]); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1287,7 +1287,7 @@ describe('Test plot api', function() { Plotly.deleteTraces(gd, [3, 0]); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1313,7 +1313,7 @@ describe('Test plot api', function() { Plotly.deleteTraces(gd, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1324,8 +1324,8 @@ describe('Test plot api', function() { beforeEach(function() { gd = { data: [{'name': 'a'}, {'name': 'b'}] }; - spyOn(PlotlyInternal, 'redraw'); - spyOn(PlotlyInternal, 'moveTraces'); + spyOn(plotApi, 'redraw'); + spyOn(plotApi, 'moveTraces'); }); it('should throw an error when traces is not an object or an array of objects', function() { @@ -1371,8 +1371,8 @@ describe('Test plot api', function() { expect(gd.data[2].uid).toBeDefined(); expect(gd.data[3].name).toBeDefined(); expect(gd.data[3].uid).toBeDefined(); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); - expect(PlotlyInternal.moveTraces).not.toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); + expect(plotApi.moveTraces).not.toHaveBeenCalled(); }); it('should work when newIndices is defined', function() { @@ -1381,8 +1381,8 @@ describe('Test plot api', function() { expect(gd.data[2].uid).toBeDefined(); expect(gd.data[3].name).toBeDefined(); expect(gd.data[3].uid).toBeDefined(); - expect(PlotlyInternal.redraw).not.toHaveBeenCalled(); - expect(PlotlyInternal.moveTraces).toHaveBeenCalledWith(gd, [-2, -1], [1, 3]); + expect(plotApi.redraw).not.toHaveBeenCalled(); + expect(plotApi.moveTraces).toHaveBeenCalledWith(gd, [-2, -1], [1, 3]); }); it('should work when newIndices has negative indices', function() { @@ -1391,16 +1391,16 @@ describe('Test plot api', function() { expect(gd.data[2].uid).toBeDefined(); expect(gd.data[3].name).toBeDefined(); expect(gd.data[3].uid).toBeDefined(); - expect(PlotlyInternal.redraw).not.toHaveBeenCalled(); - expect(PlotlyInternal.moveTraces).toHaveBeenCalledWith(gd, [-2, -1], [-3, -1]); + expect(plotApi.redraw).not.toHaveBeenCalled(); + expect(plotApi.moveTraces).toHaveBeenCalledWith(gd, [-2, -1], [-3, -1]); }); it('should work when newIndices is an integer', function() { Plotly.addTraces(gd, {'name': 'c'}, 0); expect(gd.data[2].name).toBeDefined(); expect(gd.data[2].uid).toBeDefined(); - expect(PlotlyInternal.redraw).not.toHaveBeenCalled(); - expect(PlotlyInternal.moveTraces).toHaveBeenCalledWith(gd, [-1], [0]); + expect(plotApi.redraw).not.toHaveBeenCalled(); + expect(plotApi.moveTraces).toHaveBeenCalledWith(gd, [-1], [0]); }); it('should work when adding an existing trace', function() { @@ -1430,7 +1430,7 @@ describe('Test plot api', function() { {'name': 'd'} ] }; - spyOn(PlotlyInternal, 'redraw'); + spyOn(plotApi, 'redraw'); }); it('throw an error when index arrays are unequal', function() { @@ -1498,7 +1498,7 @@ describe('Test plot api', function() { Plotly.moveTraces(gd, 0, 1); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1512,7 +1512,7 @@ describe('Test plot api', function() { Plotly.moveTraces(gd, [3, 1], [0, 3]); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1526,7 +1526,7 @@ describe('Test plot api', function() { Plotly.moveTraces(gd, [3, 0]); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); @@ -1540,7 +1540,7 @@ describe('Test plot api', function() { Plotly.moveTraces(gd, 1, -2); expect(gd.data).toEqual(expectedData); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); }); @@ -1564,7 +1564,7 @@ describe('Test plot api', function() { }; } - spyOn(PlotlyInternal, 'redraw'); + spyOn(plotApi, 'redraw'); spyOn(Plotly.Queue, 'add'); }); @@ -1666,7 +1666,7 @@ describe('Test plot api', function() { {x: [1, 2, 3, 4, 5], marker: {size: [2, 3, 4, 5, 6]}} ]); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); it('should extend and window traces with update keys', function() { @@ -1719,7 +1719,7 @@ describe('Test plot api', function() { {x: [], marker: {size: []}} ]); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); }); it('prepend is the inverse of extend - no maxPoints', function() { @@ -1823,7 +1823,7 @@ describe('Test plot api', function() { x: [args.newPts, new Float32Array(args.newPts)] }, [0, 1], args.maxp); - expect(PlotlyInternal.redraw).toHaveBeenCalled(); + expect(plotApi.redraw).toHaveBeenCalled(); expect(Plotly.Queue.add).toHaveBeenCalled(); expect(gd.data[0].x).toEqual(expectations.newArray); diff --git a/test/jasmine/tests/plotschema_test.js b/test/jasmine/tests/plotschema_test.js index a8bc35290ba..98e6fa66c9c 100644 --- a/test/jasmine/tests/plotschema_test.js +++ b/test/jasmine/tests/plotschema_test.js @@ -317,6 +317,32 @@ describe('plot schema', function() { expect(plotSchema.frames.items.frames_entry).toBeDefined(); expect(plotSchema.frames.items.frames_entry.role).toEqual('object'); }); + + it('should list trace-dependent & direction-dependent error bar attributes', function() { + var scatterSchema = plotSchema.traces.scatter.attributes; + expect(scatterSchema.error_x.copy_ystyle).toBeDefined(); + expect(scatterSchema.error_x.copy_ystyle.editType).toBe('plot'); + expect(scatterSchema.error_x.copy_zstyle).toBeUndefined(); + expect(scatterSchema.error_y.copy_ystyle).toBeUndefined(); + expect(scatterSchema.error_y.copy_zstyle).toBeUndefined(); + + var scatter3dSchema = plotSchema.traces.scatter3d.attributes; + expect(scatter3dSchema.error_x.copy_ystyle).toBeUndefined(); + expect(scatter3dSchema.error_x.copy_zstyle).toBeDefined(); + expect(scatter3dSchema.error_x.copy_zstyle.editType).toBe('calc'); + expect(scatter3dSchema.error_y.copy_ystyle).toBeUndefined(); + expect(scatter3dSchema.error_y.copy_zstyle).toBeDefined(); + expect(scatter3dSchema.error_y.copy_zstyle.editType).toBe('calc'); + expect(scatter3dSchema.error_z.copy_ystyle).toBeUndefined(); + expect(scatter3dSchema.error_z.copy_zstyle).toBeUndefined(); + + var scatterglSchema = plotSchema.traces.scattergl.attributes; + expect(scatterglSchema.error_x.copy_ystyle).toBeDefined(); + expect(scatterglSchema.error_x.copy_ystyle.editType).toBe('calc'); + expect(scatterglSchema.error_x.copy_zstyle).toBeUndefined(); + expect(scatterglSchema.error_y.copy_ystyle).toBeUndefined(); + expect(scatterglSchema.error_y.copy_zstyle).toBeUndefined(); + }); }); describe('getTraceValObject', function() { diff --git a/test/jasmine/tests/register_test.js b/test/jasmine/tests/register_test.js deleted file mode 100644 index 291561dd45c..00000000000 --- a/test/jasmine/tests/register_test.js +++ /dev/null @@ -1,329 +0,0 @@ -var Plotly = require('@lib/index'); -var Registry = require('@src/registry'); - -describe('Test Registry', function() { - 'use strict'; - - describe('register, getModule, and traceIs', function() { - beforeEach(function() { - this.modulesKeys = Object.keys(Registry.modules); - this.allTypesKeys = Object.keys(Registry.allTypes); - this.allCategoriesKeys = Object.keys(Registry.allCategories); - - this.fakeModule = { - calc: function() { return 42; }, - plot: function() { return 1000000; } - }; - this.fakeModule2 = { - plot: function() { throw new Error('nope!'); } - }; - - Registry.register(this.fakeModule, 'newtype', ['red', 'green']); - - spyOn(console, 'warn'); - }); - - afterEach(function() { - function revertObj(obj, initialKeys) { - Object.keys(obj).forEach(function(k) { - if(initialKeys.indexOf(k) === -1) delete obj[k]; - }); - } - - revertObj(Registry.modules, this.modulesKeys); - revertObj(Registry.allTypes, this.allTypesKeys); - revertObj(Registry.allCategories, this.allCategoriesKeys); - }); - - it('should not reregister a type', function() { - Registry.register(this.fakeModule2, 'newtype', ['yellow', 'blue']); - expect(Registry.allCategories.yellow).toBeUndefined(); - }); - - it('should find the module for a type', function() { - expect(Registry.getModule('newtype')).toBe(this.fakeModule); - expect(Registry.getModule({type: 'newtype'})).toBe(this.fakeModule); - }); - - it('should return false for types it doesn\'t know', function() { - expect(Registry.getModule('notatype')).toBe(false); - expect(Registry.getModule({type: 'notatype'})).toBe(false); - }); - - it('should find the categories for this type', function() { - expect(Registry.traceIs('newtype', 'red')).toBe(true); - expect(Registry.traceIs({type: 'newtype'}, 'red')).toBe(true); - }); - - it('should not find other real categories', function() { - expect(Registry.traceIs('newtype', 'cartesian')).toBe(false); - expect(Registry.traceIs({type: 'newtype'}, 'cartesian')).toBe(false); - expect(console.warn).not.toHaveBeenCalled(); - }); - }); - - describe('Registry.registerSubplot', function() { - var fake = { - name: 'fake', - attr: 'abc', - idRoot: 'cba', - attrRegex: /^abc([2-9]|[1-9][0-9]+)?$/, - idRegex: /^cba([2-9]|[1-9][0-9]+)?$/, - attributes: { stuff: { 'more stuff': 102102 } } - }; - - Registry.registerSubplot(fake); - - var subplotsRegistry = Registry.subplotsRegistry; - - it('should register attr, idRoot and attributes', function() { - expect(subplotsRegistry.fake.attr).toEqual('abc'); - expect(subplotsRegistry.fake.idRoot).toEqual('cba'); - expect(subplotsRegistry.fake.attributes) - .toEqual({stuff: { 'more stuff': 102102 }}); - }); - - describe('registered subplot type attribute regex', function() { - it('should compile to correct attribute regex string', function() { - expect(subplotsRegistry.fake.attrRegex.toString()) - .toEqual('/^abc([2-9]|[1-9][0-9]+)?$/'); - }); - - var shouldPass = [ - 'abc', 'abc2', 'abc3', 'abc10', 'abc9', 'abc100', 'abc2002' - ]; - var shouldFail = [ - '0abc', 'abc0', 'abc1', 'abc021321', 'abc00021321' - ]; - - shouldPass.forEach(function(s) { - it('considers ' + JSON.stringify(s) + 'as a correct attribute name', function() { - expect(subplotsRegistry.fake.attrRegex.test(s)).toBe(true); - }); - }); - - shouldFail.forEach(function(s) { - it('considers ' + JSON.stringify(s) + 'as an incorrect attribute name', function() { - expect(subplotsRegistry.fake.attrRegex.test(s)).toBe(false); - }); - }); - }); - - describe('registered subplot type id regex', function() { - it('should compile to correct id regular expression', function() { - expect(subplotsRegistry.fake.idRegex.toString()) - .toEqual('/^cba([2-9]|[1-9][0-9]+)?$/'); - }); - - var shouldPass = [ - 'cba', 'cba2', 'cba3', 'cba10', 'cba9', 'cba100', 'cba2002' - ]; - var shouldFail = [ - '0cba', 'cba0', 'cba1', 'cba021321', 'cba00021321' - ]; - - shouldPass.forEach(function(s) { - it('considers ' + JSON.stringify(s) + 'as a correct attribute name', function() { - expect(subplotsRegistry.fake.idRegex.test(s)).toBe(true); - }); - }); - - shouldFail.forEach(function(s) { - it('considers ' + JSON.stringify(s) + 'as an incorrect attribute name', function() { - expect(subplotsRegistry.fake.idRegex.test(s)).toBe(false); - }); - }); - }); - - }); -}); - -describe('the register function', function() { - 'use strict'; - - beforeEach(function() { - this.modulesKeys = Object.keys(Registry.modules); - this.allTypesKeys = Object.keys(Registry.allTypes); - this.allCategoriesKeys = Object.keys(Registry.allCategories); - this.allTransformsKeys = Object.keys(Registry.transformsRegistry); - }); - - afterEach(function() { - function revertObj(obj, initialKeys) { - Object.keys(obj).forEach(function(k) { - if(initialKeys.indexOf(k) === -1) delete obj[k]; - }); - } - - revertObj(Registry.modules, this.modulesKeys); - revertObj(Registry.allTypes, this.allTypesKeys); - revertObj(Registry.allCategories, this.allCategoriesKeys); - revertObj(Registry.transformsRegistry, this.allTransformsKeys); - }); - - it('should throw an error when no argument is given', function() { - expect(function() { - Plotly.register(); - }).toThrowError(Error, 'No argument passed to Plotly.register.'); - }); - - it('should work with a single module', function() { - var mockTrace1 = { - moduleType: 'trace', - name: 'mockTrace1', - meta: 'Meta string', - basePlotModule: { name: 'plotModule' }, - categories: ['categories', 'array'] - }; - - expect(function() { - Plotly.register(mockTrace1); - }).not.toThrow(); - - expect(Registry.getModule('mockTrace1')).toBe(mockTrace1); - }); - - it('should work with an array of modules', function() { - var mockTrace2 = { - moduleType: 'trace', - name: 'mockTrace2', - meta: 'Meta string', - basePlotModule: { name: 'plotModule' }, - categories: ['categories', 'array'] - }; - - expect(function() { - Plotly.register([mockTrace2]); - }).not.toThrow(); - - expect(Registry.getModule('mockTrace2')).toBe(mockTrace2); - }); - - it('should throw an error when an invalid module is given', function() { - var invalidTrace = { moduleType: 'invalid' }; - - expect(function() { - Plotly.register([invalidTrace]); - }).toThrowError(Error, 'Invalid module was attempted to be registered!'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should throw when if transform module is invalid (1)', function() { - var missingTransformName = { - moduleType: 'transform' - }; - - expect(function() { - Plotly.register(missingTransformName); - }).toThrowError(Error, 'Transform module *name* must be a string.'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should throw when if transform module is invalid (2)', function() { - var missingTransformFunc = { - moduleType: 'transform', - name: 'mah-transform' - }; - - expect(function() { - Plotly.register(missingTransformFunc); - }).toThrowError(Error, 'Transform module mah-transform is missing a *transform* or *calcTransform* method.'); - - expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); - }); - - it('should not throw when transform module is valid (1)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - transform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); - }); - - it('should not throw when transform module is valid (2)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - calcTransform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); - }); - - it('should not throw when transform module is valid (3)', function() { - var transformModule = { - moduleType: 'transform', - name: 'mah-transform', - transform: function() {}, - calcTransform: function() {} - }; - - expect(function() { - Plotly.register(transformModule); - }).not.toThrow(); - - expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); - }); - - describe('getTransformIndices', function() { - it('returns an empty array if no transforms present', function() { - expect(Registry.getTransformIndices({}, 'groupby')).toEqual([]); - }); - - it('returns an empty array if none present', function() { - expect(Registry.getTransformIndices({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'} - ] - }, 'degauss')).toEqual([]); - }); - - it('returns an empty array if none present', function() { - expect(Registry.getTransformIndices({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'}, - {type: 'groupby'} - ] - }, 'groupby')).toEqual([1, 2]); - }); - }); - - describe('hasTransform', function() { - it('returns an false array if no transforms present', function() { - expect(Registry.hasTransform({}, 'groupby')).toBe(false); - }); - - it('returns an empty array if none present', function() { - expect(Registry.hasTransform({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'} - ] - }, 'degauss')).toBe(false); - }); - - it('returns an empty array if none present', function() { - expect(Registry.hasTransform({ - transforms: [ - {type: 'filter'}, - {type: 'groupby'}, - {type: 'groupby'} - ] - }, 'groupby')).toBe(true); - }); - }); -}); diff --git a/test/jasmine/tests/registry_test.js b/test/jasmine/tests/registry_test.js new file mode 100644 index 00000000000..f37a3f37844 --- /dev/null +++ b/test/jasmine/tests/registry_test.js @@ -0,0 +1,273 @@ +var Plotly = require('@lib/index'); +var Registry = require('@src/registry'); +var Loggers = require('@src/lib/loggers'); + +describe('Test Register:', function() { + beforeAll(function() { + this.modulesKeys = Object.keys(Registry.modules); + this.allTransformsKeys = Object.keys(Registry.transformsRegistry); + this.allCategoriesKeys = Object.keys(Registry.allCategories); + this.allTypes = Registry.allTypes.slice(); + }); + + beforeEach(function() { + spyOn(Loggers, 'log'); + }); + + afterEach(function() { + function revertObj(obj, initialKeys) { + Object.keys(obj).forEach(function(k) { + if(initialKeys.indexOf(k) === -1) delete obj[k]; + }); + } + + function revertArray(arr, initial) { + arr.length = initial.length; + } + + revertObj(Registry.modules, this.modulesKeys); + revertObj(Registry.transformsRegistry, this.allTransformsKeys); + revertObj(Registry.allCategories, this.allCategoriesKeys); + revertArray(Registry.allTypes, this.allTypes); + }); + + describe('Plotly.register', function() { + var mockTrace1 = { + moduleType: 'trace', + name: 'mockTrace1', + meta: 'Meta string', + basePlotModule: { name: 'plotModule' }, + categories: ['categories', 'array'] + }; + + var mockTrace1b = { + moduleType: 'trace', + name: 'mockTrace1', + meta: 'Meta string', + basePlotModule: { name: 'plotModule' }, + categories: ['categories b', 'array b'] + }; + + var mockTrace2 = { + moduleType: 'trace', + name: 'mockTrace2', + meta: 'Meta string', + basePlotModule: { name: 'plotModule' }, + categories: ['categories', 'array'] + }; + + it('should throw an error when no argument is given', function() { + expect(function() { + Plotly.register(); + }).toThrowError(Error, 'No argument passed to Plotly.register.'); + }); + + it('should work with a single module', function() { + expect(function() { + Plotly.register(mockTrace1); + }).not.toThrow(); + + expect(Registry.getModule('mockTrace1')).toBe(mockTrace1); + expect(Registry.subplotsRegistry.plotModule).toBeDefined(); + }); + + it('should work with an array of modules', function() { + expect(function() { + Plotly.register([mockTrace2]); + }).not.toThrow(); + + expect(Registry.getModule('mockTrace2')).toBe(mockTrace2); + expect(Registry.subplotsRegistry.plotModule).toBeDefined(); + }); + + it('should throw an error when an invalid module is given', function() { + var invalidTrace = { moduleType: 'invalid' }; + + expect(function() { + Plotly.register([invalidTrace]); + }).toThrowError(Error, 'Invalid module was attempted to be registered!'); + + expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); + }); + + it('should throw when if transform module is invalid (1)', function() { + var missingTransformName = { + moduleType: 'transform' + }; + + expect(function() { + Plotly.register(missingTransformName); + }).toThrowError(Error, 'Transform module *name* must be a string.'); + + expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); + }); + + it('should throw when if transform module is invalid (2)', function() { + var missingTransformFunc = { + moduleType: 'transform', + name: 'mah-transform' + }; + + expect(function() { + Plotly.register(missingTransformFunc); + }).toThrowError(Error, 'Transform module mah-transform is missing a *transform* or *calcTransform* method.'); + + expect(Registry.transformsRegistry['mah-transform']).toBeUndefined(); + }); + + it('should not throw when transform module is valid (1)', function() { + var transformModule = { + moduleType: 'transform', + name: 'mah-transform', + transform: function() {} + }; + + expect(function() { + Plotly.register(transformModule); + }).not.toThrow(); + + expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); + }); + + it('should not throw when transform module is valid (2)', function() { + var transformModule = { + moduleType: 'transform', + name: 'mah-transform', + calcTransform: function() {} + }; + + expect(function() { + Plotly.register(transformModule); + }).not.toThrow(); + + expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); + }); + + it('should not throw when transform module is valid (3)', function() { + var transformModule = { + moduleType: 'transform', + name: 'mah-transform', + transform: function() {}, + calcTransform: function() {} + }; + + expect(function() { + Plotly.register(transformModule); + }).not.toThrow(); + + expect(Registry.transformsRegistry['mah-transform']).toBeDefined(); + }); + + it('should not reregister a trace module', function() { + Plotly.register(mockTrace1); + Plotly.register(mockTrace1b); + expect(Registry.allCategories.categories).toBe(true); + expect(Registry.allCategories.array).toBe(true); + expect(Registry.allCategories['categories b']).toBeUndefined(); + expect(Registry.allCategories['array b']).toBeUndefined(); + expect(Loggers.log).toHaveBeenCalled(); + }); + }); + + describe('Registry.getModule & Registry.traceIs:', function() { + var fakeModule = { + moduleType: 'trace', + name: 'newtype', + categories: ['red', 'green'], + calc: function() { return 42; }, + plot: function() { return 1000000; }, + basePlotModule: { name: 'newbaseplot' } + }; + + beforeEach(function() { + Registry.register(fakeModule); + }); + + it('getModule should find the module for a type', function() { + expect(Registry.getModule('newtype')).toBe(fakeModule); + expect(Registry.getModule({type: 'newtype'})).toBe(fakeModule); + expect(Loggers.log).not.toHaveBeenCalled(); + }); + + it('getModule should return false for types it doesn\'t know', function() { + expect(Registry.getModule('notatype')).toBe(false); + expect(Registry.getModule({type: 'notatype'})).toBe(false); + expect(Loggers.log).not.toHaveBeenCalled(); + }); + + it('traceIs should find the categories for this type', function() { + expect(Registry.traceIs('newtype', 'red')).toBe(true); + expect(Registry.traceIs({type: 'newtype'}, 'red')).toBe(true); + expect(Loggers.log).not.toHaveBeenCalled(); + }); + + it('traceIs should not find other real categories', function() { + expect(Registry.traceIs('newtype', 'cartesian')).toBe(false); + expect(Registry.traceIs({type: 'newtype'}, 'cartesian')).toBe(false); + expect(Loggers.log).not.toHaveBeenCalled(); + }); + + it('traceIs should log on unrecognized trace typed', function() { + expect(Registry.traceIs('nada')).toBe(false); + expect(Loggers.log).toHaveBeenCalled(); + }); + }); + + describe('Registry.getTransformIndices & Registry.hasTransform:', function() { + var transformModule = { + moduleType: 'transform', + name: 'mah-transform', + transform: function() {} + }; + + beforeEach(function() { + Plotly.register(transformModule); + }); + + it('getTransformIndices returns an empty array if no transforms present', function() { + expect(Registry.getTransformIndices({}, 'groupby')).toEqual([]); + }); + + it('getTransformIndices returns an empty array if none present', function() { + expect(Registry.getTransformIndices({ + transforms: [ + {type: 'filter'}, + {type: 'groupby'} + ] + }, 'degauss')).toEqual([]); + }); + + it('getTransformIndices returns a array of indices if transform is present', function() { + expect(Registry.getTransformIndices({ + transforms: [ + {type: 'filter'}, + {type: 'groupby'}, + {type: 'groupby'} + ] + }, 'groupby')).toEqual([1, 2]); + }); + + it('hasTransform returns false if no transforms present', function() { + expect(Registry.hasTransform({}, 'groupby')).toBe(false); + }); + + it('hasTransform returns false if none present', function() { + expect(Registry.hasTransform({ + transforms: [ + {type: 'filter'}, + {type: 'groupby'} + ] + }, 'degauss')).toBe(false); + }); + + it('hasTransform returns true if transform is present', function() { + expect(Registry.hasTransform({ + transforms: [ + {type: 'filter'}, + {type: 'groupby'}, + {type: 'groupby'} + ] + }, 'groupby')).toBe(true); + }); + }); +}); diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js index d68230c145d..c80361c0081 100644 --- a/test/jasmine/tests/shapes_test.js +++ b/test/jasmine/tests/shapes_test.js @@ -3,11 +3,9 @@ var helpers = require('@src/components/shapes/helpers'); var constants = require('@src/components/shapes/constants'); var Plotly = require('@lib/index'); -var PlotlyInternal = require('@src/plotly'); var Lib = require('@src/lib'); - -var Plots = PlotlyInternal.Plots; -var Axes = PlotlyInternal.Axes; +var Plots = require('@src/plots/plots'); +var Axes = require('@src/plots/cartesian/axes'); var d3 = require('d3'); var createGraphDiv = require('../assets/create_graph_div'); @@ -15,7 +13,6 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); var failTest = require('../assets/fail_test'); var drag = require('../assets/drag'); - describe('Test shapes defaults:', function() { 'use strict';