diff --git a/src/components/annotations/attributes.js b/src/components/annotations/attributes.js index 72484a1e2f9..8097575cf40 100644 --- a/src/components/annotations/attributes.js +++ b/src/components/annotations/attributes.js @@ -15,7 +15,7 @@ var extendFlat = require('../../lib/extend').extendFlat; module.exports = { - _isLinkedToArray: true, + _isLinkedToArray: 'annotation', visible: { valType: 'boolean', diff --git a/src/components/annotations/index.js b/src/components/annotations/index.js index ce239f1cdd7..1d4bdd09788 100644 --- a/src/components/annotations/index.js +++ b/src/components/annotations/index.js @@ -9,28 +9,16 @@ 'use strict'; -var Plotly = require('../../plotly'); - -exports.moduleType = 'component'; - -exports.name = 'annotations'; - -exports.ARROWPATHS = require('./arrow_paths'); - -exports.layoutAttributes = require('./attributes'); - -exports.supplyLayoutDefaults = require('./defaults'); - -exports.calcAutorange = require('./calc_autorange'); - -exports.arrowhead = require('./draw_arrow_head'); - var drawModule = require('./draw'); -exports.draw = drawModule.draw; -exports.drawOne = drawModule.drawOne; -exports.add = function(gd) { - var nextAnn = gd._fullLayout.annotations.length; +module.exports = { + moduleType: 'component', + name: 'annotations', + + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), - Plotly.relayout(gd, 'annotations[' + nextAnn + ']', 'add'); + calcAutorange: require('./calc_autorange'), + draw: drawModule.draw, + drawOne: drawModule.drawOne }; diff --git a/src/components/images/attributes.js b/src/components/images/attributes.js index 89a18d1c303..7f0422d3423 100644 --- a/src/components/images/attributes.js +++ b/src/components/images/attributes.js @@ -12,7 +12,7 @@ var cartesianConstants = require('../../plots/cartesian/constants'); module.exports = { - _isLinkedToArray: true, + _isLinkedToArray: 'image', visible: { valType: 'boolean', diff --git a/src/components/images/index.js b/src/components/images/index.js index 4d087e5ed36..cfac10b44ba 100644 --- a/src/components/images/index.js +++ b/src/components/images/index.js @@ -8,16 +8,12 @@ 'use strict'; - -var draw = require('./draw'); -var supplyLayoutDefaults = require('./defaults'); -var attributes = require('./attributes'); - - module.exports = { moduleType: 'component', name: 'images', - draw: draw, - layoutAttributes: attributes, - supplyLayoutDefaults: supplyLayoutDefaults + + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), + + draw: require('./draw') }; diff --git a/src/components/legend/index.js b/src/components/legend/index.js index 6a9ba017e6c..3c3c0e93d52 100644 --- a/src/components/legend/index.js +++ b/src/components/legend/index.js @@ -10,17 +10,13 @@ 'use strict'; -var legend = module.exports = {}; +module.exports = { + moduleType: 'component', + name: 'legend', + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), -legend.moduleType = 'component'; - -legend.name = 'legend'; - -legend.layoutAttributes = require('./attributes'); - -legend.supplyLayoutDefaults = require('./defaults'); - -legend.draw = require('./draw'); - -legend.style = require('./style'); + draw: require('./draw'), + style: require('./style') +}; diff --git a/src/components/rangeselector/attributes.js b/src/components/rangeselector/attributes.js index 4c4bb88128f..227903c3f26 100644 --- a/src/components/rangeselector/attributes.js +++ b/src/components/rangeselector/attributes.js @@ -14,7 +14,8 @@ var extendFlat = require('../../lib/extend').extendFlat; var buttonAttrs = require('./button_attributes'); buttonAttrs = extendFlat(buttonAttrs, { - _isLinkedToArray: true, + _isLinkedToArray: 'button', + description: [ 'Sets the specifications for each buttons.', 'By default, a range selector comes with no buttons.' diff --git a/src/components/rangeselector/index.js b/src/components/rangeselector/index.js index c284f8cc251..600a7c8e608 100644 --- a/src/components/rangeselector/index.js +++ b/src/components/rangeselector/index.js @@ -8,13 +8,13 @@ 'use strict'; +module.exports = { + moduleType: 'component', + name: 'rangeselector', -exports.moduleType = 'component'; + layoutNodes: ['xaxis.'], + layoutAttributes: require('./attributes'), + handleDefaults: require('./defaults'), -exports.name = 'rangeselector'; - -exports.layoutAttributes = require('./attributes'); - -exports.handleDefaults = require('./defaults'); - -exports.draw = require('./draw'); + draw: require('./draw') +}; diff --git a/src/components/rangeslider/index.js b/src/components/rangeslider/index.js index 1c8f3645b7a..7b652dc43c3 100644 --- a/src/components/rangeslider/index.js +++ b/src/components/rangeslider/index.js @@ -11,7 +11,10 @@ module.exports = { moduleType: 'component', name: 'rangeslider', + + layoutNodes: ['xaxis.'], layoutAttributes: require('./attributes'), handleDefaults: require('./defaults'), + draw: require('./draw') }; diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index 446a2db51bc..084f45ba5c0 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -15,7 +15,7 @@ var extendFlat = require('../../lib/extend').extendFlat; var scatterLineAttrs = scatterAttrs.line; module.exports = { - _isLinkedToArray: true, + _isLinkedToArray: 'shape', visible: { valType: 'boolean', diff --git a/src/components/shapes/index.js b/src/components/shapes/index.js index d19fd283fba..163b093f813 100644 --- a/src/components/shapes/index.js +++ b/src/components/shapes/index.js @@ -9,16 +9,16 @@ 'use strict'; -exports.moduleType = 'component'; - -exports.name = 'shapes'; - -exports.layoutAttributes = require('./attributes'); +var drawModule = require('./draw'); -exports.supplyLayoutDefaults = require('./defaults'); +module.exports = { + moduleType: 'component', + name: 'shapes', -exports.calcAutorange = require('./calc_autorange'); + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), -var drawModule = require('./draw'); -exports.draw = drawModule.draw; -exports.drawOne = drawModule.drawOne; + calcAutorange: require('./calc_autorange'), + draw: drawModule.draw, + drawOne: drawModule.drawOne +}; diff --git a/src/components/sliders/attributes.js b/src/components/sliders/attributes.js index f15bb6741ca..18d33720372 100644 --- a/src/components/sliders/attributes.js +++ b/src/components/sliders/attributes.js @@ -16,7 +16,7 @@ var animationAttrs = require('../../plots/animation_attributes'); var constants = require('./constants'); var stepsAttrs = { - _isLinkedToArray: true, + _isLinkedToArray: 'step', method: { valType: 'enumerated', @@ -57,6 +57,8 @@ var stepsAttrs = { }; module.exports = { + _isLinkedToArray: 'slider', + visible: { valType: 'boolean', role: 'info', diff --git a/src/components/sliders/constants.js b/src/components/sliders/constants.js index cb13d711d56..dbffaf81bdd 100644 --- a/src/components/sliders/constants.js +++ b/src/components/sliders/constants.js @@ -12,9 +12,8 @@ module.exports = { - // layout attribute names + // layout attribute name name: 'sliders', - itemName: 'slider', // class names containerClassName: 'slider-container', diff --git a/src/components/sliders/index.js b/src/components/sliders/index.js index 28e755fd68f..4bab63e07eb 100644 --- a/src/components/sliders/index.js +++ b/src/components/sliders/index.js @@ -8,13 +8,14 @@ 'use strict'; +var constants = require('./constants'); -exports.moduleType = 'component'; +module.exports = { + moduleType: 'component', + name: constants.name, -exports.name = 'sliders'; + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), -exports.layoutAttributes = require('./attributes'); - -exports.supplyLayoutDefaults = require('./defaults'); - -exports.draw = require('./draw'); + draw: require('./draw') +}; diff --git a/src/components/updatemenus/attributes.js b/src/components/updatemenus/attributes.js index 5efac53243b..b914443a863 100644 --- a/src/components/updatemenus/attributes.js +++ b/src/components/updatemenus/attributes.js @@ -14,7 +14,7 @@ var extendFlat = require('../../lib/extend').extendFlat; var padAttrs = require('../../plots/pad_attributes'); var buttonsAttrs = { - _isLinkedToArray: true, + _isLinkedToArray: 'button', method: { valType: 'enumerated', @@ -48,7 +48,7 @@ var buttonsAttrs = { }; module.exports = { - _isLinkedToArray: true, + _isLinkedToArray: 'updatemenu', visible: { valType: 'boolean', diff --git a/src/components/updatemenus/constants.js b/src/components/updatemenus/constants.js index 8b6cea3439b..d9f4dcdbde6 100644 --- a/src/components/updatemenus/constants.js +++ b/src/components/updatemenus/constants.js @@ -12,9 +12,8 @@ module.exports = { - // layout attribute names + // layout attribute name name: 'updatemenus', - itemName: 'updatemenu', // class names containerClassName: 'updatemenu-container', diff --git a/src/components/updatemenus/index.js b/src/components/updatemenus/index.js index 2efe17a714c..4bab63e07eb 100644 --- a/src/components/updatemenus/index.js +++ b/src/components/updatemenus/index.js @@ -8,13 +8,14 @@ 'use strict'; +var constants = require('./constants'); -exports.moduleType = 'component'; +module.exports = { + moduleType: 'component', + name: constants.name, -exports.name = 'updatemenus'; + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), -exports.layoutAttributes = require('./attributes'); - -exports.supplyLayoutDefaults = require('./defaults'); - -exports.draw = require('./draw'); + draw: require('./draw') +}; diff --git a/src/lib/coerce.js b/src/lib/coerce.js index 1b9a60095db..7d69b9e64c7 100644 --- a/src/lib/coerce.js +++ b/src/lib/coerce.js @@ -11,18 +11,12 @@ var isNumeric = require('fast-isnumeric'); var tinycolor = require('tinycolor2'); -var nestedProperty = require('./nested_property'); -var isPlainObject = require('./is_plain_object'); -var filterUnique = require('./filter_unique'); var getColorscale = require('../components/colorscale/get_scale'); var colorscaleNames = Object.keys(require('../components/colorscale/scales')); +var nestedProperty = require('./nested_property'); -var idRegex = /^([2-9]|[1-9][0-9]+)$/; - -function isValObject(obj) { - return obj && obj.valType !== undefined; -} +var ID_REGEX = /^([2-9]|[1-9][0-9]+)$/; exports.valObjects = { data_array: { @@ -174,7 +168,7 @@ exports.valObjects = { coerceFunction: function(v, propOut, dflt) { var dlen = dflt.length; if(typeof v === 'string' && v.substr(0, dlen) === dflt && - idRegex.test(v.substr(dlen))) { + ID_REGEX.test(v.substr(dlen))) { propOut.set(v); return; } @@ -186,7 +180,7 @@ exports.valObjects = { if(v === dflt) return true; if(typeof v !== 'string') return false; - if(v.substr(0, dlen) === dflt && idRegex.test(v.substr(dlen))) { + if(v.substr(0, dlen) === dflt && ID_REGEX.test(v.substr(dlen))) { return true; } @@ -361,125 +355,3 @@ exports.validate = function(value, opts) { valObject.coerceFunction(value, propMock, failed, opts); return out !== failed; }; - -/* - * returns true for a valid value object and false for tree nodes in the attribute hierarchy - */ -exports.isValObject = isValObject; - -exports.IS_SUBPLOT_OBJ = '_isSubplotObj'; -exports.IS_LINKED_TO_ARRAY = '_isLinkedToArray'; -exports.DEPRECATED = '_deprecated'; - -// list of underscore attributes to keep in schema as is -exports.UNDERSCORE_ATTRS = [exports.IS_SUBPLOT_OBJ, exports.IS_LINKED_TO_ARRAY, exports.DEPRECATED]; - -/** - * Crawl the attribute tree, recursively calling a callback function - * - * @param {object} attrs - * The node of the attribute tree (e.g. the root) from which recursion originates - * @param {Function} callback - * A callback function with the signature: - * @callback callback - * @param {object} attr an attribute - * @param {String} attrName name string - * @param {object[]} attrs all the attributes - * @param {Number} level the recursion level, 0 at the root - * @param {Number} [specifiedLevel] - * The level in the tree, in order to let the callback function detect descend or backtrack, - * typically unsupplied (implied 0), just used by the self-recursive call. - * The necessity arises because the tree traversal is not controlled by callback return values. - * The decision to not use callback return values for controlling tree pruning arose from - * the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions - * precedes the callback call. - * - * @return {object} transformOut - * copy of transformIn that contains attribute defaults - */ -exports.crawl = function(attrs, callback, specifiedLevel) { - var level = specifiedLevel || 0; - Object.keys(attrs).forEach(function(attrName) { - var attr = attrs[attrName]; - - if(exports.UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return; - - callback(attr, attrName, attrs, level); - - if(isValObject(attr)) return; - if(isPlainObject(attr)) exports.crawl(attr, callback, level + 1); - }); -}; - -/** - * Find all data array attributes in a given trace object - including - * `arrayOk` attributes. - * - * @param {object} trace - * full trace object that contains a reference to `_module.attributes` - * - * @return {array} arrayAttributes - * list of array attributes for the given trace - */ -exports.findArrayAttributes = function(trace) { - var arrayAttributes = [], - stack = []; - - /** - * A closure that gathers attribute paths into its enclosed arraySplitAttributes - * Attribute paths are collected iff their leaf node is a splittable attribute - * - * @callback callback - * @param {object} attr an attribute - * @param {String} attrName name string - * @param {object[]} attrs all the attributes - * @param {Number} level the recursion level, 0 at the root - * - * @closureVariable {String[][]} arrayAttributes the set of gathered attributes - * Example of filled closure variable (expected to be initialized to []): - * [["marker","size"],["marker","line","width"],["marker","line","color"]] - */ - function callback(attr, attrName, attrs, level) { - stack = stack.slice(0, level).concat([attrName]); - - var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true; - if(!splittableAttr) return; - - var astr = toAttrString(stack); - var val = nestedProperty(trace, astr).get(); - if(!Array.isArray(val)) return; - - arrayAttributes.push(astr); - } - - function toAttrString(stack) { - return stack.join('.'); - } - - exports.crawl(trace._module.attributes, callback); - - if(trace.transforms) { - var transforms = trace.transforms; - - for(var i = 0; i < transforms.length; i++) { - var transform = transforms[i]; - - stack = ['transforms[' + i + ']']; - exports.crawl(transform._module.attributes, callback, 1); - } - } - - // Look into the fullInput module attributes for array attributes - // to make sure that 'custom' array attributes are detected. - // - // At the moment, we need this block to make sure that - // ohlc and candlestick 'open', 'high', 'low', 'close' can be - // used with filter ang groupby transforms. - if(trace._fullInput) { - exports.crawl(trace._fullInput._module.attributes, callback); - - arrayAttributes = filterUnique(arrayAttributes); - } - - return arrayAttributes; -}; diff --git a/src/lib/index.js b/src/lib/index.js index d0ca7757003..3239693a4d7 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -23,13 +23,6 @@ lib.coerce = coerceModule.coerce; lib.coerce2 = coerceModule.coerce2; lib.coerceFont = coerceModule.coerceFont; lib.validate = coerceModule.validate; -lib.isValObject = coerceModule.isValObject; -lib.crawl = coerceModule.crawl; -lib.findArrayAttributes = coerceModule.findArrayAttributes; -lib.IS_SUBPLOT_OBJ = coerceModule.IS_SUBPLOT_OBJ; -lib.IS_LINKED_TO_ARRAY = coerceModule.IS_LINKED_TO_ARRAY; -lib.DEPRECATED = coerceModule.DEPRECATED; -lib.UNDERSCORE_ATTRS = coerceModule.UNDERSCORE_ATTRS; var datesModule = require('./dates'); lib.dateTime2ms = datesModule.dateTime2ms; diff --git a/src/plot_api/plot_schema.js b/src/plot_api/plot_schema.js index 52f5d913b79..972835dbfb2 100644 --- a/src/plot_api/plot_schema.js +++ b/src/plot_api/plot_schema.js @@ -9,185 +9,287 @@ 'use strict'; -var Plotly = require('../plotly'); var Registry = require('../registry'); -var Plots = require('../plots/plots'); var Lib = require('../lib'); -// FIXME polar attribute are not part of Plotly yet +var baseAttributes = require('../plots/attributes'); +var baseLayoutAttributes = require('../plots/layout_attributes'); +var frameAttributes = require('../plots/frame_attributes'); +var animationAttributes = require('../plots/animation_attributes'); + +// polar attributes are not part of the Registry yet var polarAreaAttrs = require('../plots/polar/area_attributes'); var polarAxisAttrs = require('../plots/polar/axis_attributes'); var extendFlat = Lib.extendFlat; var extendDeep = Lib.extendDeep; -var extendDeepAll = Lib.extendDeepAll; -var NESTED_MODULE = '_nestedModules', - COMPOSED_MODULE = '_composedModules'; +var IS_SUBPLOT_OBJ = '_isSubplotObj'; +var IS_LINKED_TO_ARRAY = '_isLinkedToArray'; +var DEPRECATED = '_deprecated'; +var UNDERSCORE_ATTRS = [IS_SUBPLOT_OBJ, IS_LINKED_TO_ARRAY, DEPRECATED]; + +exports.IS_SUBPLOT_OBJ = IS_SUBPLOT_OBJ; +exports.IS_LINKED_TO_ARRAY = IS_LINKED_TO_ARRAY; +exports.DEPRECATED = DEPRECATED; +exports.UNDERSCORE_ATTRS = UNDERSCORE_ATTRS; + +/** Outputs the full plotly.js plot schema + * + * @return {object} + * - defs + * - traces + * - layout + * - transforms + * - frames + * - animations + * - config (coming soon ...) + */ +exports.get = function() { + var traces = {}; + + Registry.allTypes.concat('area').forEach(function(type) { + traces[type] = getTraceAttributes(type); + }); + + var transforms = {}; + + Object.keys(Registry.transformsRegistry).forEach(function(type) { + transforms[type] = getTransformAttributes(type); + }); + + return { + defs: { + valObjects: Lib.valObjects, + metaKeys: UNDERSCORE_ATTRS.concat['description', 'role'] + }, -var plotSchema = { - traces: {}, - layout: {}, - transforms: {}, - defs: {} + traces: traces, + layout: getLayoutAttributes(), + + transforms: transforms, + + frames: formatAttributes(frameAttributes), + animation: formatAttributes(animationAttributes) + }; }; +/** + * Crawl the attribute tree, recursively calling a callback function + * + * @param {object} attrs + * The node of the attribute tree (e.g. the root) from which recursion originates + * @param {Function} callback + * A callback function with the signature: + * @callback callback + * @param {object} attr an attribute + * @param {String} attrName name string + * @param {object[]} attrs all the attributes + * @param {Number} level the recursion level, 0 at the root + * @param {Number} [specifiedLevel] + * The level in the tree, in order to let the callback function detect descend or backtrack, + * typically unsupplied (implied 0), just used by the self-recursive call. + * The necessity arises because the tree traversal is not controlled by callback return values. + * The decision to not use callback return values for controlling tree pruning arose from + * the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions + * precedes the callback call. + * + * @return {object} transformOut + * copy of transformIn that contains attribute defaults + */ +exports.crawl = function(attrs, callback, specifiedLevel) { + var level = specifiedLevel || 0; + + Object.keys(attrs).forEach(function(attrName) { + var attr = attrs[attrName]; + + if(UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return; + + callback(attr, attrName, attrs, level); + + if(exports.isValObject(attr)) return; + + if(Lib.isPlainObject(attr)) exports.crawl(attr, callback, level + 1); + }); +}; + +/** Is object a value object (or a container object)? + * + * @param {object} obj + * @return {boolean} + * returns true for a valid value object and + * false for tree nodes in the attribute hierarchy + */ +exports.isValObject = function(obj) { + return obj && obj.valType !== undefined; +}; -var PlotSchema = module.exports = {}; +/** + * Find all data array attributes in a given trace object - including + * `arrayOk` attributes. + * + * @param {object} trace + * full trace object that contains a reference to `_module.attributes` + * + * @return {array} arrayAttributes + * list of array attributes for the given trace + */ +exports.findArrayAttributes = function(trace) { + var arrayAttributes = [], + stack = []; + + function callback(attr, attrName, attrs, level) { + stack = stack.slice(0, level).concat([attrName]); + + var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true; + if(!splittableAttr) return; + + var astr = toAttrString(stack); + var val = Lib.nestedProperty(trace, astr).get(); + if(!Array.isArray(val)) return; + + arrayAttributes.push(astr); + } + function toAttrString(stack) { + return stack.join('.'); + } -PlotSchema.get = function() { - Registry.allTypes - .concat('area') // FIXME polar 'area' attributes - .forEach(getTraceAttributes); + exports.crawl(trace._module.attributes, callback); - getLayoutAttributes(); + if(trace.transforms) { + var transforms = trace.transforms; - Object.keys(Registry.transformsRegistry).forEach(getTransformAttributes); + for(var i = 0; i < transforms.length; i++) { + var transform = transforms[i]; - getDefs(); + stack = ['transforms[' + i + ']']; + exports.crawl(transform._module.attributes, callback, 1); + } + } - return plotSchema; -}; + // Look into the fullInput module attributes for array attributes + // to make sure that 'custom' array attributes are detected. + // + // At the moment, we need this block to make sure that + // ohlc and candlestick 'open', 'high', 'low', 'close' can be + // used with filter ang groupby transforms. + if(trace._fullInput) { + exports.crawl(trace._fullInput._module.attributes, callback); -PlotSchema.crawl = Lib.crawl; + arrayAttributes = Lib.filterUnique(arrayAttributes); + } -PlotSchema.isValObject = Lib.isValObject; + return arrayAttributes; +}; function getTraceAttributes(type) { - var globalAttributes = Plots.attributes, - _module = getModule({type: type}), - meta = getMeta(type), - subplotRegistry = getSubplotRegistry(type); + var _module, basePlotModule; + + if(type === 'area') { + _module = { attributes: polarAreaAttrs }; + basePlotModule = {}; + } + else { + _module = Registry.modules[type]._module, + basePlotModule = _module.basePlotModule; + } - var attributes = {}, - layoutAttributes = {}; + var attributes = {}; // make 'type' the first attribute in the object attributes.type = null; - // global attributes (same for all trace types) - extendDeep(attributes, globalAttributes); + // base attributes (same for all trace types) + extendDeep(attributes, baseAttributes); - // module attributes (+ nested + composed) - attributes = coupleAttrs( - _module.attributes, attributes, 'attributes', type - ); + // module attributes + extendDeep(attributes, _module.attributes); // subplot attributes - if(subplotRegistry.attributes !== undefined) { - extendDeep(attributes, subplotRegistry.attributes); + if(basePlotModule.attributes) { + extendDeep(attributes, basePlotModule.attributes); } - // 'type' gets overwritten by globalAttributes; reset it here + // 'type' gets overwritten by baseAttributes; reset it here attributes.type = type; - attributes = removeUnderscoreAttrs(attributes); - mergeValTypeAndRole(attributes); - plotSchema.traces[type] = extendFlat({}, - meta, - { attributes: attributes } - ); + var out = { + meta: _module.meta || {}, + attributes: formatAttributes(attributes), + }; // trace-specific layout attributes - if(_module.layoutAttributes !== undefined) { - layoutAttributes = coupleAttrs( - _module.layoutAttributes, layoutAttributes, 'layoutAttributes', type - ); + if(_module.layoutAttributes) { + var layoutAttributes = {}; - mergeValTypeAndRole(layoutAttributes); - plotSchema.traces[type].layoutAttributes = layoutAttributes; + extendDeep(layoutAttributes, _module.layoutAttributes); + out.layoutAttributes = formatAttributes(layoutAttributes); } + + return out; } function getLayoutAttributes() { - var globalLayoutAttributes = Plots.layoutAttributes, - layoutAttributes = {}; + var layoutAttributes = {}; - // layout module attributes (+ nested + composed) - layoutAttributes = coupleAttrs( - globalLayoutAttributes, layoutAttributes, 'layoutAttributes', '*' - ); + // global layout attributes + extendDeep(layoutAttributes, baseLayoutAttributes); - // FIXME polar layout attributes - layoutAttributes = assignPolarLayoutAttrs(layoutAttributes); - - // add crawler.IS_SUBPLOT_OBJ attribute - layoutAttributes = handleSubplotObjs(layoutAttributes); - - layoutAttributes = removeUnderscoreAttrs(layoutAttributes); - mergeValTypeAndRole(layoutAttributes); + // add base plot module layout attributes + Object.keys(Registry.subplotsRegistry).forEach(function(k) { + var _module = Registry.subplotsRegistry[k]; - // generate crawler.IS_LINKED_TO_ARRAY structure - handleLinkedToArray(layoutAttributes); - - plotSchema.layout = { layoutAttributes: layoutAttributes }; -} + if(!_module.layoutAttributes) return; -function getTransformAttributes(name) { - var _module = Registry.transformsRegistry[name], - _schema = {}; - - _schema = coupleAttrs(_schema, _module.attributes || {}, 'attributes', '*'); - _schema = removeUnderscoreAttrs(_schema); - mergeValTypeAndRole(_schema); - handleLinkedToArray(_schema); - - plotSchema.transforms[name] = { attributes: _schema }; -} - -function getDefs() { - plotSchema.defs = { - valObjects: Lib.valObjects, - metaKeys: Lib.UNDERSCORE_ATTRS.concat(['description', 'role']) - }; -} + if(_module.name === 'cartesian') { + handleBasePlotModule(layoutAttributes, _module, 'xaxis'); + handleBasePlotModule(layoutAttributes, _module, 'yaxis'); + } + else { + var astr = _module.attr === 'subplot' ? _module.name : _module.attr; -function coupleAttrs(attrsIn, attrsOut, whichAttrs, type) { - var nestedModule, nestedAttrs, nestedReference, - composedModule, composedAttrs; + handleBasePlotModule(layoutAttributes, _module, astr); + } + }); - Object.keys(attrsIn).forEach(function(k) { + // polar layout attributes + layoutAttributes = assignPolarLayoutAttrs(layoutAttributes); - if(k === NESTED_MODULE) { - Object.keys(attrsIn[k]).forEach(function(kk) { - nestedModule = getModule({_module: attrsIn[k][kk]}); - if(nestedModule === undefined) return; + // add registered components layout attribute + Object.keys(Registry.componentsRegistry).forEach(function(k) { + var _module = Registry.componentsRegistry[k]; - nestedAttrs = nestedModule[whichAttrs]; - nestedReference = coupleAttrs( - nestedAttrs, {}, whichAttrs, type - ); + if(!_module.layoutAttributes) return; - Lib.nestedProperty(attrsOut, kk) - .set(extendDeep({}, nestedReference)); + if(Array.isArray(_module.layoutNodes)) { + _module.layoutNodes.forEach(function(v) { + handleRegisteredComponent(layoutAttributes, _module, v + _module.name); }); - return; } + else { + handleRegisteredComponent(layoutAttributes, _module, _module.name); + } + }); - if(k === COMPOSED_MODULE) { - Object.keys(attrsIn[k]).forEach(function(kk) { - if(kk !== type) return; - - composedModule = getModule({_module: attrsIn[k][kk]}); - if(composedModule === undefined) return; + return { + layoutAttributes: formatAttributes(layoutAttributes) + }; +} - composedAttrs = composedModule[whichAttrs]; - composedAttrs = coupleAttrs( - composedAttrs, {}, whichAttrs, type - ); +function getTransformAttributes(type) { + var _module = Registry.transformsRegistry[type]; - extendDeepAll(attrsOut, composedAttrs); - }); - return; - } + return { + attributes: formatAttributes(_module.attributes) + }; +} - attrsOut[k] = Lib.isPlainObject(attrsIn[k]) ? - extendDeepAll({}, attrsIn[k]) : - attrsIn[k]; - }); +function formatAttributes(attrs) { + mergeValTypeAndRole(attrs); + formatArrayContainers(attrs); - return attrsOut; + return attrs; } function mergeValTypeAndRole(attrs) { @@ -204,7 +306,7 @@ function mergeValTypeAndRole(attrs) { } function callback(attr, attrName, attrs) { - if(PlotSchema.isValObject(attr)) { + if(exports.isValObject(attr)) { if(attr.valType === 'data_array') { // all 'data_array' attrs have role 'data' attr.role = 'data'; @@ -222,40 +324,26 @@ function mergeValTypeAndRole(attrs) { } } - Lib.crawl(attrs, callback); + exports.crawl(attrs, callback); } -// helper methods +function formatArrayContainers(attrs) { -function getModule(arg) { - if('type' in arg) { - return (arg.type === 'area') ? // FIXME - { attributes: polarAreaAttrs } : - Registry.getModule({type: arg.type}); - } + function callback(attr, attrName, attrs) { + if(!attr) return; - var subplotsRegistry = Registry.subplotsRegistry, - componentsRegistry = Registry.componentsRegistry, - _module = arg._module; + var itemName = attr[IS_LINKED_TO_ARRAY]; - if(subplotsRegistry[_module]) return subplotsRegistry[_module]; - else if(componentsRegistry[_module]) return componentsRegistry[_module]; + if(!itemName) return; - // look it internal Plotly if all previous attempts fail - return Plotly[_module]; -} + delete attr[IS_LINKED_TO_ARRAY]; -function removeUnderscoreAttrs(attributes) { - Object.keys(attributes).forEach(function(k) { - if(k.charAt(0) === '_' && - Lib.UNDERSCORE_ATTRS.indexOf(k) === -1) delete attributes[k]; - }); - return attributes; -} + attrs[attrName] = { items: {} }; + attrs[attrName].items[itemName] = attr; + attrs[attrName].role = 'object'; + } -function getMeta(type) { - if(type === 'area') return {}; // FIXME - return Registry.modules[type].meta || {}; + exports.crawl(attrs, callback); } function assignPolarLayoutAttrs(layoutAttributes) { @@ -266,63 +354,20 @@ function assignPolarLayoutAttrs(layoutAttributes) { extendFlat(layoutAttributes, polarAxisAttrs.layout); - return layoutAttributes; // FIXME -} - -function getSubplotRegistry(traceType) { - if(traceType === 'area') return {}; // FIXME - - var subplotsRegistry = Registry.subplotsRegistry, - subplotType = Object.keys(subplotsRegistry).filter(function(subplotType) { - return Registry.traceIs({type: traceType}, subplotType); - })[0]; - - if(subplotType === undefined) return {}; - - return subplotsRegistry[subplotType]; -} - -function handleSubplotObjs(layoutAttributes) { - var subplotsRegistry = Registry.subplotsRegistry; - - Object.keys(layoutAttributes).forEach(function(k) { - Object.keys(subplotsRegistry).forEach(function(subplotType) { - var subplotRegistry = subplotsRegistry[subplotType], - isSubplotObj; - - if(!subplotRegistry.attrRegex) return; - - if(subplotType === 'cartesian' || subplotType === 'gl2d') { - isSubplotObj = ( - subplotRegistry.attrRegex.x.test(k) || - subplotRegistry.attrRegex.y.test(k) - ); - } - else { - isSubplotObj = subplotRegistry.attrRegex.test(k); - } - - if(isSubplotObj) layoutAttributes[k][Lib.IS_SUBPLOT_OBJ] = true; - }); - }); - return layoutAttributes; } -function handleLinkedToArray(layoutAttributes) { - - function callback(attr, attrName, attrs) { - if(attr[Lib.IS_LINKED_TO_ARRAY] !== true) return; - - // TODO more robust logic - var itemName = attrName.substr(0, attrName.length - 1); +function handleBasePlotModule(layoutAttributes, _module, astr) { + var np = Lib.nestedProperty(layoutAttributes, astr), + attrs = extendDeep({}, _module.layoutAttributes); - delete attr[Lib.IS_LINKED_TO_ARRAY]; + attrs[IS_SUBPLOT_OBJ] = true; + np.set(attrs); +} - attrs[attrName] = { items: {} }; - attrs[attrName].items[itemName] = attr; - attrs[attrName].role = 'object'; - } +function handleRegisteredComponent(layoutAttributes, _module, astr) { + var np = Lib.nestedProperty(layoutAttributes, astr), + attrs = extendDeep(np.get() || {}, _module.layoutAttributes); - Lib.crawl(layoutAttributes, callback); + np.set(attrs); } diff --git a/src/plot_api/register.js b/src/plot_api/register.js index 5192b95a99c..04bdd00c1d9 100644 --- a/src/plot_api/register.js +++ b/src/plot_api/register.js @@ -89,5 +89,9 @@ function registerTransformModule(newModule) { } function registerComponentModule(newModule) { - Registry.componentsRegistry[newModule.name] = 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/validate.js b/src/plot_api/validate.js index d034cca38d1..f27781a7884 100644 --- a/src/plot_api/validate.js +++ b/src/plot_api/validate.js @@ -173,7 +173,8 @@ function crawl(objIn, objOut, schema, list, base, path) { crawl(valIn, valOut, nestedSchema, list, base, p); } else if(nestedSchema.items && !isInfoArray && isArray(valIn)) { - var itemName = k.substr(0, k.length - 1), + var items = nestedSchema.items, + _nestedSchema = items[Object.keys(items)[0]], indexList = []; var j, _p; @@ -181,8 +182,7 @@ function crawl(objIn, objOut, schema, list, base, path) { // loop over valOut items while keeping track of their // corresponding input container index (given by _index) for(j = 0; j < valOut.length; j++) { - var _nestedSchema = nestedSchema.items[itemName], - _index = valOut[j]._index || j; + var _index = valOut[j]._index || j; _p = p.slice(); _p.push(_index); diff --git a/src/plotly.js b/src/plotly.js index 899696c639c..2ac2da1bec8 100644 --- a/src/plotly.js +++ b/src/plotly.js @@ -25,19 +25,6 @@ exports.defaultConfig = require('./plot_api/plot_config'); exports.Plots = require('./plots/plots'); exports.Axes = require('./plots/cartesian/axes'); exports.Fx = require('./plots/cartesian/graph_interact'); - -// components -exports.Color = require('./components/color'); -exports.Drawing = require('./components/drawing'); -exports.Colorscale = require('./components/colorscale'); -exports.Colorbar = require('./components/colorbar'); -exports.ErrorBars = require('./components/errorbars'); -exports.Annotations = require('./components/annotations'); -exports.Shapes = require('./components/shapes'); -exports.Legend = require('./components/legend'); -exports.Images = require('./components/images'); -exports.UpdateMenus = require('./components/updatemenus'); -exports.Sliders = require('./components/sliders'); exports.ModeBar = require('./components/modebar'); // plot api diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index e205b6d2e56..10408f47ac7 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -23,6 +23,7 @@ var dragElement = require('../../components/dragelement'); var Axes = require('./axes'); var constants = require('./constants'); var dragBox = require('./dragbox'); +var layoutAttributes = require('../layout_attributes'); var fx = module.exports = {}; @@ -32,29 +33,12 @@ var fx = module.exports = {}; fx.unhover = dragElement.unhover; fx.layoutAttributes = { - dragmode: { - valType: 'enumerated', - role: 'info', - values: ['zoom', 'pan', 'select', 'lasso', 'orbit', 'turntable'], - dflt: 'zoom', - description: [ - 'Determines the mode of drag interactions.', - '*select* and *lasso* apply only to scatter traces with', - 'markers or text. *orbit* and *turntable* apply only to', - '3D scenes.' - ].join(' ') - }, - hovermode: { - valType: 'enumerated', - role: 'info', - values: ['x', 'y', 'closest', false], - description: 'Determines the mode of hover interactions.' - } }; fx.supplyLayoutDefaults = function(layoutIn, layoutOut, fullData) { + function coerce(attr, dflt) { - return Lib.coerce(layoutIn, layoutOut, fx.layoutAttributes, attr, dflt); + return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt); } coerce('dragmode'); diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index e643a1fd3c5..381be90d62a 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -27,6 +27,8 @@ exports.attrRegex = constants.attrRegex; exports.attributes = require('./attributes'); +exports.layoutAttributes = require('./layout_attributes'); + exports.transitionAxes = require('./transition_axes'); exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 89f0f9dcbdc..630aa677855 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -518,11 +518,6 @@ module.exports = { ].join(' ') }, - _nestedModules: { - 'rangeslider': 'rangeslider', - 'rangeselector': 'rangeselector', - }, - _deprecated: { autotick: { valType: 'boolean', diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index ced39429096..f98ffc9606f 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -171,23 +171,22 @@ module.exports = { description: 'Determines whether or not a legend is drawn.' }, - _composedModules: { - '*': 'Fx' + dragmode: { + valType: 'enumerated', + role: 'info', + values: ['zoom', 'pan', 'select', 'lasso', 'orbit', 'turntable'], + dflt: 'zoom', + description: [ + 'Determines the mode of drag interactions.', + '*select* and *lasso* apply only to scatter traces with', + 'markers or text. *orbit* and *turntable* apply only to', + '3D scenes.' + ].join(' ') }, - - _nestedModules: { - 'xaxis': 'Axes', - 'yaxis': 'Axes', - 'scene': 'gl3d', - 'geo': 'geo', - 'ternary': 'ternary', - 'mapbox': 'mapbox', - - 'legend': 'legend', - 'annotations': 'annotations', - 'shapes': 'shapes', - 'images': 'images', - 'updatemenus': 'updatemenus', - 'sliders': 'sliders' + hovermode: { + valType: 'enumerated', + role: 'info', + values: ['x', 'y', 'closest', false], + description: 'Determines the mode of hover interactions.' } }; diff --git a/src/plots/mapbox/layout_attributes.js b/src/plots/mapbox/layout_attributes.js index 3aa94e890f4..b116b53cdc1 100644 --- a/src/plots/mapbox/layout_attributes.js +++ b/src/plots/mapbox/layout_attributes.js @@ -105,7 +105,7 @@ module.exports = { }, layers: { - _isLinkedToArray: true, + _isLinkedToArray: 'layer', sourcetype: { valType: 'enumerated', diff --git a/src/plots/plots.js b/src/plots/plots.js index 6f8e5ff578a..b365272fd30 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -1614,7 +1614,7 @@ plots.extendObjectWithContainers = function(dest, src, containerPaths) { }; plots.dataArrayContainers = ['transforms']; -plots.layoutArrayContainers = ['annotations', 'shapes', 'images', 'sliders', 'updatemenus']; +plots.layoutArrayContainers = Registry.layoutArrayContainers; /* * Extend a trace definition. This method: diff --git a/src/registry.js b/src/registry.js index 4b59b261581..73e0ee198ac 100644 --- a/src/registry.js +++ b/src/registry.js @@ -13,11 +13,12 @@ var Lib = require('./lib'); var basePlotAttributes = require('./plots/attributes'); exports.modules = {}; -exports.allTypes = []; exports.allCategories = {}; +exports.allTypes = []; exports.subplotsRegistry = {}; exports.transformsRegistry = {}; exports.componentsRegistry = {}; +exports.layoutArrayContainers = []; /** * register a module as the handler for a trace type @@ -83,6 +84,16 @@ exports.registerSubplot = function(_module) { exports.subplotsRegistry[plotType] = _module; }; +exports.registerComponent = function(_module) { + var name = _module.name; + + exports.componentsRegistry[name] = _module; + + if(_module.layoutAttributes && _module.layoutAttributes._isLinkedToArray) { + Lib.pushUnique(exports.layoutArrayContainers, name); + } +}; + /** * Get registered module using trace object or trace type * diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js index c5659f56611..26436e87656 100644 --- a/src/traces/bar/attributes.js +++ b/src/traces/bar/attributes.js @@ -10,6 +10,9 @@ 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 extendFlat = require('../../lib/extend').extendFlat; var scatterMarkerAttrs = scatterAttrs.marker; @@ -23,9 +26,11 @@ var markerLine = extendFlat({}, { }, colorAttributes('marker.line')); var marker = extendFlat({}, { - showscale: scatterMarkerAttrs.showscale, line: markerLine -}, colorAttributes('marker')); +}, colorAttributes('marker'), { + showscale: scatterMarkerAttrs.showscale, + colorbar: colorbarAttrs +}); module.exports = { @@ -91,11 +96,8 @@ module.exports = { r: scatterAttrs.r, t: scatterAttrs.t, - _nestedModules: { // nested module coupling - 'error_y': 'ErrorBars', - 'error_x': 'ErrorBars', - 'marker.colorbar': 'Colorbar' - }, + error_y: errorBarAttrs, + error_x: errorBarAttrs, _deprecated: { bardir: { diff --git a/src/traces/choropleth/attributes.js b/src/traces/choropleth/attributes.js index 3cd9735997f..c57db2710f6 100644 --- a/src/traces/choropleth/attributes.js +++ b/src/traces/choropleth/attributes.js @@ -10,7 +10,9 @@ var ScatterGeoAttrs = require('../scattergeo/attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var plotAttrs = require('../../plots/attributes'); + var extendFlat = require('../../lib/extend').extendFlat; var ScatterGeoMarkerLineAttrs = ScatterGeoAttrs.marker.line; @@ -41,9 +43,7 @@ module.exports = extendFlat({}, { hoverinfo: extendFlat({}, plotAttrs.hoverinfo, { flags: ['location', 'z', 'text', 'name'] }), - _nestedModules: { - 'colorbar': 'Colorbar' - } }, - colorscaleAttrs + colorscaleAttrs, + { colorbar: colorbarAttrs } ); diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index a0822e2b979..9849d3f06bb 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -11,114 +11,111 @@ var heatmapAttrs = require('../heatmap/attributes'); var scatterAttrs = require('../scatter/attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var extendFlat = require('../../lib/extend').extendFlat; var scatterLineAttrs = scatterAttrs.line; -module.exports = extendFlat({}, - { - z: heatmapAttrs.z, - x: heatmapAttrs.x, - x0: heatmapAttrs.x0, - dx: heatmapAttrs.dx, - y: heatmapAttrs.y, - y0: heatmapAttrs.y0, - dy: heatmapAttrs.dy, - text: heatmapAttrs.text, - transpose: heatmapAttrs.transpose, - xtype: heatmapAttrs.xtype, - ytype: heatmapAttrs.ytype, +module.exports = extendFlat({}, { + z: heatmapAttrs.z, + x: heatmapAttrs.x, + x0: heatmapAttrs.x0, + dx: heatmapAttrs.dx, + y: heatmapAttrs.y, + y0: heatmapAttrs.y0, + dy: heatmapAttrs.dy, + text: heatmapAttrs.text, + transpose: heatmapAttrs.transpose, + xtype: heatmapAttrs.xtype, + ytype: heatmapAttrs.ytype, - connectgaps: heatmapAttrs.connectgaps, + connectgaps: heatmapAttrs.connectgaps, - autocontour: { - valType: 'boolean', - dflt: true, + autocontour: { + valType: 'boolean', + dflt: true, + role: 'style', + description: [ + 'Determines whether or not the contour level attributes are', + 'picked by an algorithm.', + 'If *true*, the number of contour levels can be set in `ncontours`.', + 'If *false*, set the contour level attributes in `contours`.' + ].join(' ') + }, + ncontours: { + valType: 'integer', + dflt: 0, + role: 'style', + description: [ + 'Sets the maximum number of contour levels. The actual number', + 'of contours will be chosen automatically to be less than or', + 'equal to the value of `ncontours`.', + 'Has an effect only if `autocontour` is *true*.' + ].join(' ') + }, + + contours: { + start: { + valType: 'number', + dflt: null, + role: 'style', + description: 'Sets the starting contour level value.' + }, + end: { + valType: 'number', + dflt: null, + role: 'style', + description: 'Sets the end contour level value.' + }, + size: { + valType: 'number', + dflt: null, + role: 'style', + description: 'Sets the step between each contour level.' + }, + coloring: { + valType: 'enumerated', + values: ['fill', 'heatmap', 'lines', 'none'], + dflt: 'fill', role: 'style', description: [ - 'Determines whether or not the contour level attributes are', - 'picked by an algorithm.', - 'If *true*, the number of contour levels can be set in `ncontours`.', - 'If *false*, set the contour level attributes in `contours`.' + 'Determines the coloring method showing the contour values.', + 'If *fill*, coloring is done evenly between each contour level', + 'If *heatmap*, a heatmap gradient coloring is applied', + 'between each contour level.', + 'If *lines*, coloring is done on the contour lines.', + 'If *none*, no coloring is applied on this trace.' ].join(' ') }, - ncontours: { - valType: 'integer', - dflt: 0, + showlines: { + valType: 'boolean', + dflt: true, role: 'style', description: [ - 'Sets the maximum number of contour levels. The actual number', - 'of contours will be chosen automatically to be less than or', - 'equal to the value of `ncontours`.', - 'Has an effect only if `autocontour` is *true*.' + 'Determines whether or not the contour lines are drawn.', + 'Has only an effect if `contours.coloring` is set to *fill*.' ].join(' ') - }, - - contours: { - start: { - valType: 'number', - dflt: null, - role: 'style', - description: 'Sets the starting contour level value.' - }, - end: { - valType: 'number', - dflt: null, - role: 'style', - description: 'Sets the end contour level value.' - }, - size: { - valType: 'number', - dflt: null, - role: 'style', - description: 'Sets the step between each contour level.' - }, - coloring: { - valType: 'enumerated', - values: ['fill', 'heatmap', 'lines', 'none'], - dflt: 'fill', - role: 'style', - description: [ - 'Determines the coloring method showing the contour values.', - 'If *fill*, coloring is done evenly between each contour level', - 'If *heatmap*, a heatmap gradient coloring is applied', - 'between each contour level.', - 'If *lines*, coloring is done on the contour lines.', - 'If *none*, no coloring is applied on this trace.' - ].join(' ') - }, - showlines: { - valType: 'boolean', - dflt: true, - role: 'style', - description: [ - 'Determines whether or not the contour lines are drawn.', - 'Has only an effect if `contours.coloring` is set to *fill*.' - ].join(' ') - } - }, - - line: { - color: extendFlat({}, scatterLineAttrs.color, { - description: [ - 'Sets the color of the contour level.', - 'Has no if `contours.coloring` is set to *lines*.' - ].join(' ') - }), - width: scatterLineAttrs.width, - dash: scatterLineAttrs.dash, - smoothing: extendFlat({}, scatterLineAttrs.smoothing, { - description: [ - 'Sets the amount of smoothing for the contour lines,', - 'where *0* corresponds to no smoothing.' - ].join(' ') - }) - }, - - _nestedModules: { - 'colorbar': 'Colorbar' } }, + + line: { + color: extendFlat({}, scatterLineAttrs.color, { + description: [ + 'Sets the color of the contour level.', + 'Has no if `contours.coloring` is set to *lines*.' + ].join(' ') + }), + width: scatterLineAttrs.width, + dash: scatterLineAttrs.dash, + smoothing: extendFlat({}, scatterLineAttrs.smoothing, { + description: [ + 'Sets the amount of smoothing for the contour lines,', + 'where *0* corresponds to no smoothing.' + ].join(' ') + }) + } +}, colorscaleAttrs, - {autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false})} + { autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false}) }, + { colorbar: colorbarAttrs } ); diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 8155a2f8ea2..da86b34d004 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -10,90 +10,88 @@ var scatterAttrs = require('../scatter/attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var extendFlat = require('../../lib/extend').extendFlat; -module.exports = extendFlat({}, - { - z: { - valType: 'data_array', - description: 'Sets the z data.' - }, - x: scatterAttrs.x, - x0: scatterAttrs.x0, - dx: scatterAttrs.dx, - y: scatterAttrs.y, - y0: scatterAttrs.y0, - dy: scatterAttrs.dy, - text: { - valType: 'data_array', - description: 'Sets the text elements associated with each z value.' - }, - transpose: { - valType: 'boolean', - dflt: false, - role: 'info', - description: 'Transposes the z data.' - }, - xtype: { - valType: 'enumerated', - values: ['array', 'scaled'], - role: 'info', - description: [ - 'If *array*, the heatmap\'s x coordinates are given by *x*', - '(the default behavior when `x` is provided).', - 'If *scaled*, the heatmap\'s x coordinates are given by *x0* and *dx*', - '(the default behavior when `x` is not provided).' - ].join(' ') - }, - ytype: { - valType: 'enumerated', - values: ['array', 'scaled'], - role: 'info', - description: [ - 'If *array*, the heatmap\'s y coordinates are given by *y*', - '(the default behavior when `y` is provided)', - 'If *scaled*, the heatmap\'s y coordinates are given by *y0* and *dy*', - '(the default behavior when `y` is not provided)' - ].join(' ') - }, - zsmooth: { - valType: 'enumerated', - values: ['fast', 'best', false], - dflt: false, - role: 'style', - description: [ - 'Picks a smoothing algorithm use to smooth `z` data.' - ].join(' ') - }, - connectgaps: { - valType: 'boolean', - dflt: false, - role: 'info', - description: [ - 'Determines whether or not gaps', - '(i.e. {nan} or missing values)', - 'in the `z` data are filled in.' - ].join(' ') - }, - xgap: { - valType: 'number', - dflt: 0, - min: 0, - role: 'style', - description: 'Sets the horizontal gap (in pixels) between bricks.' - }, - ygap: { - valType: 'number', - dflt: 0, - min: 0, - role: 'style', - description: 'Sets the vertical gap (in pixels) between bricks.' - }, - _nestedModules: { - 'colorbar': 'Colorbar' - } +module.exports = extendFlat({}, { + z: { + valType: 'data_array', + description: 'Sets the z data.' }, + x: scatterAttrs.x, + x0: scatterAttrs.x0, + dx: scatterAttrs.dx, + y: scatterAttrs.y, + y0: scatterAttrs.y0, + dy: scatterAttrs.dy, + text: { + valType: 'data_array', + description: 'Sets the text elements associated with each z value.' + }, + transpose: { + valType: 'boolean', + dflt: false, + role: 'info', + description: 'Transposes the z data.' + }, + xtype: { + valType: 'enumerated', + values: ['array', 'scaled'], + role: 'info', + description: [ + 'If *array*, the heatmap\'s x coordinates are given by *x*', + '(the default behavior when `x` is provided).', + 'If *scaled*, the heatmap\'s x coordinates are given by *x0* and *dx*', + '(the default behavior when `x` is not provided).' + ].join(' ') + }, + ytype: { + valType: 'enumerated', + values: ['array', 'scaled'], + role: 'info', + description: [ + 'If *array*, the heatmap\'s y coordinates are given by *y*', + '(the default behavior when `y` is provided)', + 'If *scaled*, the heatmap\'s y coordinates are given by *y0* and *dy*', + '(the default behavior when `y` is not provided)' + ].join(' ') + }, + zsmooth: { + valType: 'enumerated', + values: ['fast', 'best', false], + dflt: false, + role: 'style', + description: [ + 'Picks a smoothing algorithm use to smooth `z` data.' + ].join(' ') + }, + connectgaps: { + valType: 'boolean', + dflt: false, + role: 'info', + description: [ + 'Determines whether or not gaps', + '(i.e. {nan} or missing values)', + 'in the `z` data are filled in.' + ].join(' ') + }, + xgap: { + valType: 'number', + dflt: 0, + min: 0, + role: 'style', + description: 'Sets the horizontal gap (in pixels) between bricks.' + }, + ygap: { + valType: 'number', + dflt: 0, + min: 0, + role: 'style', + description: 'Sets the vertical gap (in pixels) between bricks.' + }, +}, colorscaleAttrs, - {autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false})} + { autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false}) }, + { colorbar: colorbarAttrs } ); diff --git a/src/traces/histogram/attributes.js b/src/traces/histogram/attributes.js index 757c923c190..650c4e42a3a 100644 --- a/src/traces/histogram/attributes.js +++ b/src/traces/histogram/attributes.js @@ -121,11 +121,8 @@ module.exports = { marker: barAttrs.marker, - _nestedModules: { - 'error_y': 'ErrorBars', - 'error_x': 'ErrorBars', - 'marker.colorbar': 'Colorbar' - }, + error_y: barAttrs.error_y, + error_x: barAttrs.error_x, _deprecated: { bardir: barAttrs._deprecated.bardir diff --git a/src/traces/histogram2d/attributes.js b/src/traces/histogram2d/attributes.js index 6421274e54b..c6c6d87445a 100644 --- a/src/traces/histogram2d/attributes.js +++ b/src/traces/histogram2d/attributes.js @@ -11,6 +11,7 @@ var histogramAttrs = require('../histogram/attributes'); var heatmapAttrs = require('../heatmap/attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var extendFlat = require('../../lib/extend').extendFlat; @@ -41,12 +42,9 @@ module.exports = extendFlat({}, xgap: heatmapAttrs.xgap, ygap: heatmapAttrs.ygap, - zsmooth: heatmapAttrs.zsmooth, - - _nestedModules: { - 'colorbar': 'Colorbar' - } + zsmooth: heatmapAttrs.zsmooth }, colorscaleAttrs, - {autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false})} + { autocolorscale: extendFlat({}, colorscaleAttrs.autocolorscale, {dflt: false}) }, + { colorbar: colorbarAttrs } ); diff --git a/src/traces/histogram2dcontour/attributes.js b/src/traces/histogram2dcontour/attributes.js index 6442ddc58d5..49a1ca72596 100644 --- a/src/traces/histogram2dcontour/attributes.js +++ b/src/traces/histogram2dcontour/attributes.js @@ -11,6 +11,7 @@ var histogram2dAttrs = require('../histogram2d/attributes'); var contourAttrs = require('../contour/attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var extendFlat = require('../../lib/extend').extendFlat; @@ -32,11 +33,8 @@ module.exports = extendFlat({}, { autocontour: contourAttrs.autocontour, ncontours: contourAttrs.ncontours, contours: contourAttrs.contours, - line: contourAttrs.line, - - _nestedModules: { - 'colorbar': 'Colorbar' - } + line: contourAttrs.line }, - colorscaleAttrs + colorscaleAttrs, + { colorbar: colorbarAttrs } ); diff --git a/src/traces/mesh3d/attributes.js b/src/traces/mesh3d/attributes.js index ea9082d6a36..c726e23c03d 100644 --- a/src/traces/mesh3d/attributes.js +++ b/src/traces/mesh3d/attributes.js @@ -9,7 +9,9 @@ 'use strict'; var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var surfaceAtts = require('../surface/attributes'); + var extendFlat = require('../../lib/extend').extendFlat; @@ -166,6 +168,7 @@ module.exports = { colorscale: colorscaleAttrs.colorscale, reversescale: colorscaleAttrs.reversescale, showscale: colorscaleAttrs.showscale, + colorbar: colorbarAttrs, lightposition: { 'x': extendFlat({}, surfaceAtts.lightposition.x, {dflt: 1e5}), @@ -189,9 +192,5 @@ module.exports = { dflt: 1e-6, // even the brain model doesn't appear to need finer than this description: 'Epsilon for face normals calculation avoids math issues arising from degenerate geometry.' } - }, surfaceAtts.lighting), - - _nestedModules: { // nested module coupling - 'colorbar': 'Colorbar' - } + }, surfaceAtts.lighting) }; diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index d9f83dd78ce..1a728047d4d 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -9,11 +9,11 @@ 'use strict'; var colorAttributes = require('../../components/colorscale/color_attributes'); +var errorBarAttrs = require('../../components/errorbars/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var Drawing = require('../../components/drawing'); - var constants = require('./constants'); - var extendFlat = require('../../lib/extend').extendFlat; module.exports = { @@ -281,6 +281,7 @@ module.exports = { 'to pixels.' ].join(' ') }, + showscale: { valType: 'boolean', role: 'info', @@ -290,6 +291,8 @@ module.exports = { 'Determines whether or not a colorbar is displayed.' ].join(' ') }, + colorbar: colorbarAttrs, + line: extendFlat({}, { width: { valType: 'number', @@ -340,6 +343,7 @@ module.exports = { }, description: 'Sets the text font.' }, + r: { valType: 'data_array', description: [ @@ -354,9 +358,7 @@ module.exports = { 'Sets the angular coordinates.' ].join('') }, - _nestedModules: { // nested module coupling - 'error_y': 'ErrorBars', - 'error_x': 'ErrorBars', - 'marker.colorbar': 'Colorbar' - } + + error_y: errorBarAttrs, + error_x: errorBarAttrs }; diff --git a/src/traces/scatter3d/attributes.js b/src/traces/scatter3d/attributes.js index 06b1cecc708..5208068b5de 100644 --- a/src/traces/scatter3d/attributes.js +++ b/src/traces/scatter3d/attributes.js @@ -10,6 +10,7 @@ var scatterAttrs = require('../scatter/attributes'); var colorAttributes = require('../../components/colorscale/color_attributes'); +var errorBarAttrs = require('../../components/errorbars/attributes'); var MARKER_SYMBOLS = require('../../constants/gl_markers'); var extendFlat = require('../../lib/extend').extendFlat; @@ -137,6 +138,8 @@ module.exports = { ].join(' ') }), showscale: scatterMarkerAttrs.showscale, + colorbar: scatterMarkerAttrs.colorbar, + line: extendFlat({}, {width: extendFlat({}, scatterMarkerLineAttrs.width, {arrayOk: false})}, colorAttributes('marker.line') @@ -144,12 +147,11 @@ module.exports = { }, colorAttributes('marker') ), + textposition: extendFlat({}, scatterAttrs.textposition, {dflt: 'top center'}), textfont: scatterAttrs.textfont, - _nestedModules: { - 'error_x': 'ErrorBars', - 'error_y': 'ErrorBars', - 'error_z': 'ErrorBars', - 'marker.colorbar': 'Colorbar' - } + + error_x: errorBarAttrs, + error_y: errorBarAttrs, + error_z: errorBarAttrs, }; diff --git a/src/traces/scattergeo/attributes.js b/src/traces/scattergeo/attributes.js index d7f68c40234..caa667cac27 100644 --- a/src/traces/scattergeo/attributes.js +++ b/src/traces/scattergeo/attributes.js @@ -77,6 +77,7 @@ module.exports = { sizemin: scatterMarkerAttrs.sizemin, sizemode: scatterMarkerAttrs.sizemode, showscale: scatterMarkerAttrs.showscale, + colorbar: scatterMarkerAttrs.colorbar, line: extendFlat({}, {width: scatterMarkerLineAttrs.width}, colorAttributes('marker.line') @@ -101,9 +102,5 @@ module.exports = { hoverinfo: extendFlat({}, plotAttrs.hoverinfo, { flags: ['lon', 'lat', 'location', 'text', 'name'] - }), - - _nestedModules: { - 'marker.colorbar': 'Colorbar' - } + }) }; diff --git a/src/traces/scattergl/attributes.js b/src/traces/scattergl/attributes.js index 50a123dd66e..55c8b2681a8 100644 --- a/src/traces/scattergl/attributes.js +++ b/src/traces/scattergl/attributes.js @@ -71,6 +71,7 @@ module.exports = { sizemode: scatterMarkerAttrs.sizemode, opacity: scatterMarkerAttrs.opacity, showscale: scatterMarkerAttrs.showscale, + colorbar: scatterMarkerAttrs.colorbar, line: extendDeep({}, colorAttributes('marker.line'), { width: scatterMarkerLineAttrs.width }) @@ -80,9 +81,7 @@ module.exports = { values: ['none', 'tozeroy', 'tozerox'] }), fillcolor: scatterAttrs.fillcolor, - _nestedModules: { - 'error_x': 'ErrorBars', - 'error_y': 'ErrorBars', - 'marker.colorbar': 'Colorbar' - } + + error_y: scatterAttrs.error_y, + error_x: scatterAttrs.error_x }; diff --git a/src/traces/scattermapbox/attributes.js b/src/traces/scattermapbox/attributes.js index a4fdd03e1de..12efedebbe7 100644 --- a/src/traces/scattermapbox/attributes.js +++ b/src/traces/scattermapbox/attributes.js @@ -12,6 +12,8 @@ var scatterGeoAttrs = require('../scattergeo/attributes'); var scatterAttrs = require('../scatter/attributes'); var mapboxAttrs = require('../../plots/mapbox/layout_attributes'); var plotAttrs = require('../../plots/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); + var extendFlat = require('../../lib/extend').extendFlat; var lineAttrs = scatterGeoAttrs.line; @@ -86,7 +88,8 @@ module.exports = { cmin: markerAttrs.cmin, autocolorscale: markerAttrs.autocolorscale, reversescale: markerAttrs.reversescale, - showscale: markerAttrs.showscale + showscale: markerAttrs.showscale, + colorbar: colorbarAttrs // line }, @@ -100,8 +103,4 @@ module.exports = { hoverinfo: extendFlat({}, plotAttrs.hoverinfo, { flags: ['lon', 'lat', 'text', 'name'] }), - - _nestedModules: { - 'marker.colorbar': 'Colorbar' - } }; diff --git a/src/traces/scatterternary/attributes.js b/src/traces/scatterternary/attributes.js index fb28327b348..c973948f59e 100644 --- a/src/traces/scatterternary/attributes.js +++ b/src/traces/scatterternary/attributes.js @@ -11,6 +11,7 @@ var scatterAttrs = require('../scatter/attributes'); var plotAttrs = require('../../plots/attributes'); var colorAttributes = require('../../components/colorscale/color_attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); var extendFlat = require('../../lib/extend').extendFlat; @@ -104,21 +105,19 @@ module.exports = { sizeref: scatterMarkerAttrs.sizeref, sizemin: scatterMarkerAttrs.sizemin, sizemode: scatterMarkerAttrs.sizemode, - showscale: scatterMarkerAttrs.showscale, line: extendFlat({}, {width: scatterMarkerLineAttrs.width}, colorAttributes('marker'.line) ) - }, - colorAttributes('marker') - ), + }, colorAttributes('marker'), { + showscale: scatterMarkerAttrs.showscale, + colorbar: colorbarAttrs + }), + textfont: scatterAttrs.textfont, textposition: scatterAttrs.textposition, hoverinfo: extendFlat({}, plotAttrs.hoverinfo, { flags: ['a', 'b', 'c', 'text', 'name'] }), hoveron: scatterAttrs.hoveron, - _nestedModules: { - 'marker.colorbar': 'Colorbar' - } }; diff --git a/src/traces/surface/attributes.js b/src/traces/surface/attributes.js index b10531a4262..7bd693a1894 100644 --- a/src/traces/surface/attributes.js +++ b/src/traces/surface/attributes.js @@ -10,6 +10,8 @@ var Color = require('../../components/color'); var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); + var extendFlat = require('../../lib/extend').extendFlat; function makeContourProjAttr(axLetter) { @@ -128,6 +130,7 @@ module.exports = { {dflt: false}), reversescale: colorscaleAttrs.reversescale, showscale: colorscaleAttrs.showscale, + colorbar: colorbarAttrs, contours: { x: makeContourAttr('x'), @@ -228,10 +231,6 @@ module.exports = { description: 'Sets the opacity of the surface.' }, - _nestedModules: { // nested module coupling - 'colorbar': 'Colorbar' - }, - _deprecated: { zauto: extendFlat({}, colorscaleAttrs.zauto, { description: 'Obsolete. Use `cauto` instead.' diff --git a/src/transforms/filter.js b/src/transforms/filter.js index ca39d0861a8..b1c6d704b2e 100644 --- a/src/transforms/filter.js +++ b/src/transforms/filter.js @@ -9,6 +9,7 @@ 'use strict'; var Lib = require('../lib'); +var PlotSchema = require('../plot_api/plot_schema'); var axisIds = require('../plots/cartesian/axis_ids'); var autoType = require('../plots/cartesian/axis_autotype'); var setConvert = require('../plots/cartesian/set_convert'); @@ -131,7 +132,7 @@ exports.calcTransform = function(gd, trace, opts) { var dataToCoord = getDataToCoordFunc(gd, trace, target), filterFunc = getFilterFunc(opts, dataToCoord), - arrayAttrs = Lib.findArrayAttributes(trace), + arrayAttrs = PlotSchema.findArrayAttributes(trace), originalArrays = {}; // copy all original array attribute values, diff --git a/src/transforms/groupby.js b/src/transforms/groupby.js index 0cce190eab3..b038b9539b1 100644 --- a/src/transforms/groupby.js +++ b/src/transforms/groupby.js @@ -9,6 +9,7 @@ 'use strict'; var Lib = require('../lib'); +var PlotSchema = require('../plot_api/plot_schema'); exports.moduleType = 'transform'; @@ -125,7 +126,7 @@ function transformOne(trace, state) { newData = new Array(groupNames.length), len = groups.length; - var arrayAttrs = Lib.findArrayAttributes(trace); + var arrayAttrs = PlotSchema.findArrayAttributes(trace); var style = opts.style || {}; diff --git a/tasks/test_syntax.js b/tasks/test_syntax.js index 8d28447bbe8..4f2326c92cb 100644 --- a/tasks/test_syntax.js +++ b/tasks/test_syntax.js @@ -105,7 +105,7 @@ function assertCircularDeps() { // as of v1.17.0 - 2016/09/08 // see https://github.com/plotly/plotly.js/milestone/9 // for more details - var MAX_ALLOWED_CIRCULAR_DEPS = 34; + var MAX_ALLOWED_CIRCULAR_DEPS = 17; if(circularDeps.length > MAX_ALLOWED_CIRCULAR_DEPS) { logs.push('some new circular dependencies were added to src/'); diff --git a/test/jasmine/tests/plotschema_test.js b/test/jasmine/tests/plotschema_test.js index fa822c23fdf..ec7b4819fe4 100644 --- a/test/jasmine/tests/plotschema_test.js +++ b/test/jasmine/tests/plotschema_test.js @@ -1,4 +1,5 @@ var Plotly = require('@lib/index'); + var Lib = require('@src/lib'); describe('plot schema', function() { @@ -88,7 +89,7 @@ describe('plot schema', function() { it('all subplot objects should contain _isSubplotObj', function() { var IS_SUBPLOT_OBJ = '_isSubplotObj', astrs = ['xaxis', 'yaxis', 'scene', 'geo', 'ternary', 'mapbox'], - list = []; + cnt = 0; // check if the subplot objects have '_isSubplotObj' astrs.forEach(function(astr) { @@ -103,16 +104,22 @@ describe('plot schema', function() { // check that no other object has '_isSubplotObj' assertPlotSchema( function(attr, attrName) { - if(attr[IS_SUBPLOT_OBJ] === true) list.push(attrName); + if(attr[IS_SUBPLOT_OBJ] === true) { + expect(astrs.indexOf(attrName)).not.toEqual(-1); + cnt++; + } } ); - expect(list).toEqual(astrs); + + expect(cnt).toEqual(astrs.length); }); it('should convert _isLinkedToArray attributes to items object', function() { var astrs = [ 'annotations', 'shapes', 'images', - 'xaxis.rangeselector.buttons', 'yaxis.rangeselector.buttons', + 'xaxis.rangeselector.buttons', + 'updatemenus', + 'sliders', 'mapbox.layers' ];