From 09816309d1ce4b3a4e91c324172a713367e56c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:13:13 -0400 Subject: [PATCH 01/10] use lib directly in build/plotcss.js --- build/plotcss.js | 4 ++-- tasks/util/pull_css.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/plotcss.js b/build/plotcss.js index 169edfce295..4594c5d52b7 100644 --- a/build/plotcss.js +++ b/build/plotcss.js @@ -1,6 +1,6 @@ 'use strict'; -var Plotly = require('../src/plotly'); +var Lib = require('../src/lib'); var rules = { "X,X div": "font-family:'Open Sans', verdana, arial, sans-serif;margin:0;padding:0;", "X input,X button": "font-family:'Open Sans', verdana, arial, sans-serif;", @@ -58,5 +58,5 @@ for(var selector in rules) { var fullSelector = selector.replace(/^,/,' ,') .replace(/X/g, '.js-plotly-plot .plotly') .replace(/Y/g, '.plotly-notifier'); - Plotly.Lib.addStyleRule(fullSelector, rules[selector]); + Lib.addStyleRule(fullSelector, rules[selector]); } diff --git a/tasks/util/pull_css.js b/tasks/util/pull_css.js index 1f3cb6def53..145013b1994 100644 --- a/tasks/util/pull_css.js +++ b/tasks/util/pull_css.js @@ -38,14 +38,14 @@ module.exports = function pullCSS(data, pathOut) { var outStr = [ '\'use strict\';', '', - 'var Plotly = require(\'../src/plotly\');', + 'var Lib = require(\'../src/lib\');', 'var rules = ' + rulesStr + ';', '', 'for(var selector in rules) {', ' var fullSelector = selector.replace(/^,/,\' ,\')', ' .replace(/X/g, \'.js-plotly-plot .plotly\')', ' .replace(/Y/g, \'.plotly-notifier\');', - ' Plotly.Lib.addStyleRule(fullSelector, rules[selector]);', + ' Lib.addStyleRule(fullSelector, rules[selector]);', '}', '' ].join('\n'); From d625f01f42f70dce2654b8bd7329f4f0d75cdf91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:15:06 -0400 Subject: [PATCH 02/10] legend: don't require Plotly --- src/components/legend/draw.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 0e8d9f88600..1cb17bd8880 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -17,6 +17,7 @@ var Plots = require('../../plots/plots'); var dragElement = require('../dragelement'); var Drawing = require('../drawing'); var Color = require('../color'); +var svgTextUtils = require('../../lib/svg_text_utils'); var constants = require('./constants'); var getLegendData = require('./get_legend_data'); @@ -354,14 +355,14 @@ function drawTexts(g, gd) { .text(name); function textLayout(s) { - Plotly.util.convertToTspans(s, function() { + svgTextUtils.convertToTspans(s, function() { s.selectAll('tspan.line').attr({x: s.attr('x')}); g.call(computeTextDimensions, gd); }); } if(gd._context.editable && !isPie) { - text.call(Plotly.util.makeEditable) + text.call(svgTextUtils.makeEditable) .call(textLayout) .on('edit', function(text) { this.attr({'data-unformatted': text}); From 210ff6d79e9ba975b24a886bbbb5548e8f4dff6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:15:15 -0400 Subject: [PATCH 03/10] modebar: don't require Plotly --- src/components/modebar/buttons.js | 14 ++++++++------ src/components/modebar/manage.js | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 23b6ae8a72c..18e4280abcc 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -10,6 +10,8 @@ 'use strict'; var Plotly = require('../../plotly'); +var Plots = require('../../plots/plots'); +var Axes = require('../../plots/cartesian/axes'); var Lib = require('../../lib'); var downloadImage = require('../../snapshot/download'); var Icons = require('../../../build/ploticon'); @@ -72,7 +74,7 @@ modeBarButtons.sendDataToCloud = { title: 'Save and edit plot in cloud', icon: Icons.disk, click: function(gd) { - Plotly.Plots.sendDataToCloud(gd); + Plots.sendDataToCloud(gd); } }; @@ -181,7 +183,7 @@ function handleCartesian(gd, ev) { var mag = (val === 'in') ? 0.5 : 2, r0 = (1 + mag) / 2, r1 = (1 - mag) / 2, - axList = Plotly.Axes.list(gd, null, true); + axList = Axes.list(gd, null, true); var ax, axName; @@ -263,7 +265,7 @@ function handleDrag3d(gd, ev) { attr = button.getAttribute('data-attr'), val = button.getAttribute('data-val') || true, fullLayout = gd._fullLayout, - sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'), + sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d'), layoutUpdate = {}; var parts = attr.split('.'); @@ -295,7 +297,7 @@ function handleCamera3d(gd, ev) { var button = ev.currentTarget, attr = button.getAttribute('data-attr'), fullLayout = gd._fullLayout, - sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'); + sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d'); for(var i = 0; i < sceneIds.length; i++) { var sceneId = sceneIds[i], @@ -327,7 +329,7 @@ function handleHover3d(gd, ev) { val = button._previousVal || false, layout = gd.layout, fullLayout = gd._fullLayout, - sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'); + sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d'); var axes = ['xaxis', 'yaxis', 'zaxis'], spikeAttrs = ['showspikes', 'spikesides', 'spikethickness', 'spikecolor']; @@ -415,7 +417,7 @@ function handleGeo(gd, ev) { attr = button.getAttribute('data-attr'), val = button.getAttribute('data-val') || true, fullLayout = gd._fullLayout, - geoIds = Plotly.Plots.getSubplotIds(fullLayout, 'geo'); + geoIds = Plots.getSubplotIds(fullLayout, 'geo'); for(var i = 0; i < geoIds.length; i++) { var geo = fullLayout[geoIds[i]]._geo; diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index eacfabbfe3b..1ed905461fe 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -9,7 +9,7 @@ 'use strict'; -var Plotly = require('../../plotly'); +var Axes = require('../../plots/cartesian/axes'); var scatterSubTypes = require('../../traces/scatter/subtypes'); var createModeBar = require('./'); @@ -148,7 +148,7 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) { } function areAllAxesFixed(fullLayout) { - var axList = Plotly.Axes.list({_fullLayout: fullLayout}, null, true); + var axList = Axes.list({_fullLayout: fullLayout}, null, true); var allFixed = true; for(var i = 0; i < axList.length; i++) { From 3042ccb6b4d8df7d214489fcceddee9eb113ccdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:20:54 -0400 Subject: [PATCH 04/10] snapshot: rm circular dep patterns - by adding a `snapshot/helpers.js` module --- src/plot_api/to_image.js | 8 +------- src/snapshot/cloneplot.js | 9 +++++---- src/snapshot/helpers.js | 31 +++++++++++++++++++++++++++++++ src/snapshot/index.js | 25 +++---------------------- src/snapshot/toimage.js | 19 ++++++++++--------- 5 files changed, 50 insertions(+), 42 deletions(-) create mode 100644 src/snapshot/helpers.js diff --git a/src/plot_api/to_image.js b/src/plot_api/to_image.js index 0da4a7dbd48..5be7957a2c0 100644 --- a/src/plot_api/to_image.js +++ b/src/plot_api/to_image.js @@ -12,6 +12,7 @@ var isNumeric = require('fast-isnumeric'); var Plotly = require('../plotly'); var Lib = require('../lib'); +var Snapshot = require('../snapshot'); /** @@ -22,7 +23,6 @@ var Lib = require('../lib'); * @param opts.height height of snapshot in px */ function toImage(gd, opts) { - var Snapshot = require('../snapshot'); var promise = new Promise(function(resolve, reject) { // check for undefined opts @@ -91,12 +91,6 @@ function toImage(gd, opts) { var redrawFunc = Snapshot.getRedrawFunc(clonedGd); Plotly.plot(clonedGd, clone.data, clone.layout, clone.config) - // TODO: the following is Plotly.Plots.redrawText but without the waiting. - // we shouldn't need to do this, but in *occasional* cases we do. Figure - // out why and take it out. - - // not sure the above TODO makes sense anymore since - // we have converted to promises .then(redrawFunc) .then(wait) .then(function(url) { resolve(url); }) diff --git a/src/snapshot/cloneplot.js b/src/snapshot/cloneplot.js index b7ac366017b..d8f076b0d7f 100644 --- a/src/snapshot/cloneplot.js +++ b/src/snapshot/cloneplot.js @@ -9,10 +9,11 @@ 'use strict'; -var Plotly = require('../plotly'); +var Lib = require('../lib'); +var Plots = require('../plots/plots'); -var extendFlat = Plotly.Lib.extendFlat; -var extendDeep = Plotly.Lib.extendDeep; +var extendFlat = Lib.extendFlat; +var extendDeep = Lib.extendDeep; // Put default plotTile layouts here function cloneLayoutOverride(tileClass) { @@ -99,7 +100,7 @@ module.exports = function clonePlot(graphObj, options) { } } - var sceneIds = Plotly.Plots.getSubplotIds(newLayout, 'gl3d'); + var sceneIds = Plots.getSubplotIds(newLayout, 'gl3d'); if(sceneIds.length) { var axesImageOverride = {}; diff --git a/src/snapshot/helpers.js b/src/snapshot/helpers.js new file mode 100644 index 00000000000..83799b38ed2 --- /dev/null +++ b/src/snapshot/helpers.js @@ -0,0 +1,31 @@ +/** +* Copyright 2012-2016, 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'; + +exports.getDelay = function(fullLayout) { + + // polar clears fullLayout._has for some reason + if(!fullLayout._has) return 0; + + // maybe we should add a 'gl' (and 'svg') layoutCategory ?? + return (fullLayout._has('gl3d') || fullLayout._has('gl2d')) ? 500 : 0; +}; + +exports.getRedrawFunc = function(gd) { + + // do not work if polar is present + if((gd.data && gd.data[0] && gd.data[0].r)) return; + + return function() { + (gd.calcdata || []).forEach(function(d) { + if(d[0] && d[0].t && d[0].t.cb) d[0].t.cb(); + }); + }; +}; diff --git a/src/snapshot/index.js b/src/snapshot/index.js index 4cbe774aa9c..673277e5f71 100644 --- a/src/snapshot/index.js +++ b/src/snapshot/index.js @@ -9,30 +9,11 @@ 'use strict'; -function getDelay(fullLayout) { - - // polar clears fullLayout._has for some reason - if(!fullLayout._has) return 0; - - // maybe we should add a 'gl' (and 'svg') layoutCategory ?? - return (fullLayout._has('gl3d') || fullLayout._has('gl2d')) ? 500 : 0; -} - -function getRedrawFunc(gd) { - - // do not work if polar is present - if((gd.data && gd.data[0] && gd.data[0].r)) return; - - return function() { - (gd.calcdata || []).forEach(function(d) { - if(d[0] && d[0].t && d[0].t.cb) d[0].t.cb(); - }); - }; -} +var helpers = require('./helpers'); var Snapshot = { - getDelay: getDelay, - getRedrawFunc: getRedrawFunc, + getDelay: helpers.getDelay, + getRedrawFunc: helpers.getRedrawFunc, clone: require('./cloneplot'), toSVG: require('./tosvg'), svgToImg: require('./svgtoimg'), diff --git a/src/snapshot/toimage.js b/src/snapshot/toimage.js index b66ab3eacc5..9fc8eb75b5a 100644 --- a/src/snapshot/toimage.js +++ b/src/snapshot/toimage.js @@ -13,6 +13,11 @@ var EventEmitter = require('events').EventEmitter; var Plotly = require('../plotly'); var Lib = require('../lib'); +var helpers = require('./helpers'); +var clonePlot = require('./cloneplot'); +var toSVG = require('./tosvg'); +var svgToImg = require('./svgtoimg'); + /** * @param {object} gd figure Object @@ -22,10 +27,9 @@ var Lib = require('../lib'); function toImage(gd, opts) { // first clone the GD so we can operate in a clean environment - var Snapshot = Plotly.Snapshot; var ev = new EventEmitter(); - var clone = Snapshot.clone(gd, {format: 'png'}); + var clone = clonePlot(gd, {format: 'png'}); var clonedGd = clone.td; // put the cloned div somewhere off screen before attaching to DOM @@ -34,15 +38,15 @@ function toImage(gd, opts) { document.body.appendChild(clonedGd); function wait() { - var delay = Snapshot.getDelay(clonedGd._fullLayout); + var delay = helpers.getDelay(clonedGd._fullLayout); setTimeout(function() { - var svg = Plotly.Snapshot.toSVG(clonedGd); + var svg = toSVG(clonedGd); var canvas = document.createElement('canvas'); canvas.id = Lib.randstr(); - ev = Plotly.Snapshot.svgToImg({ + ev = svgToImg({ format: opts.format, width: clonedGd._fullLayout.width, height: clonedGd._fullLayout.height, @@ -58,12 +62,9 @@ function toImage(gd, opts) { }, delay); } - var redrawFunc = Snapshot.getRedrawFunc(clonedGd); + var redrawFunc = helpers.getRedrawFunc(clonedGd); Plotly.plot(clonedGd, clone.data, clone.layout, clone.config) - // TODO: the following is Plotly.Plots.redrawText but without the waiting. - // we shouldn't need to do this, but in *occasional* cases we do. Figure - // out why and take it out. .then(redrawFunc) .then(wait) .catch(function(err) { From b7d89698973a11b45f7a8c866946a4d44453cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:22:00 -0400 Subject: [PATCH 05/10] a couple more "don't require Plotly" --- src/plots/cartesian/graph_interact.js | 2 +- src/plots/layout_attributes.js | 5 ++--- src/traces/bar/style.js | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 540577d922c..a367d6e65b3 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -447,7 +447,7 @@ function hover(gd, evt, subplot) { else yvalArray = p2c(yaArray, ypx); if(!isNumeric(xvalArray[0]) || !isNumeric(yvalArray[0])) { - Lib.warn('Plotly.Fx.hover failed', evt, gd); + Lib.warn('Fx.hover failed', evt, gd); return dragElement.unhoverRaw(gd, evt); } } diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 05a0e598535..33aa018153b 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -8,12 +8,11 @@ 'use strict'; -var Plotly = require('../plotly'); - var fontAttrs = require('./font_attributes'); var colorAttrs = require('../components/color/attributes'); -var extendFlat = Plotly.Lib.extendFlat; +var Lib = require('../lib'); +var extendFlat = Lib.extendFlat; module.exports = { diff --git a/src/traces/bar/style.js b/src/traces/bar/style.js index 6d5835da6f2..a976340c3ae 100644 --- a/src/traces/bar/style.js +++ b/src/traces/bar/style.js @@ -70,7 +70,7 @@ module.exports = function style(gd) { }); // TODO: text markers on bars, either extra text or just bar values // d3.select(this).selectAll('text') - // .call(Plotly.Drawing.textPointStyle,d.t||d[0].t); + // .call(Drawing.textPointStyle,d.t||d[0].t); }); s.call(ErrorBars.style); From dc043ae4f76847ffe2b071f4d5b90c4b11874586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Mon, 8 Aug 2016 18:26:10 -0400 Subject: [PATCH 06/10] gl3d: don't require Plotly --- src/plots/gl3d/layout/tick_marks.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plots/gl3d/layout/tick_marks.js b/src/plots/gl3d/layout/tick_marks.js index be602485668..ec6558405b0 100644 --- a/src/plots/gl3d/layout/tick_marks.js +++ b/src/plots/gl3d/layout/tick_marks.js @@ -13,7 +13,8 @@ module.exports = computeTickMarks; -var Plotly = require('../../../plotly'); +var Axes = require('../../cartesian/axes'); +var Lib = require('../../../lib'); var convertHTMLToUnicode = require('../../../lib/html2unicode'); var AXES_NAMES = ['xaxis', 'yaxis', 'zaxis']; @@ -64,10 +65,10 @@ function computeTickMarks(scene) { var tickModeCached = axes.tickmode; if(axes.tickmode === 'auto') { axes.tickmode = 'linear'; - var nticks = axes.nticks || Plotly.Lib.constrain((axes._length / 40), 4, 9); - Plotly.Axes.autoTicks(axes, Math.abs(axes.range[1] - axes.range[0]) / nticks); + var nticks = axes.nticks || Lib.constrain((axes._length / 40), 4, 9); + Axes.autoTicks(axes, Math.abs(axes.range[1] - axes.range[0]) / nticks); } - var dataTicks = Plotly.Axes.calcTicks(axes); + var dataTicks = Axes.calcTicks(axes); for(var j = 0; j < dataTicks.length; ++j) { dataTicks[j].x = dataTicks[j].x * scene.dataScale[i]; dataTicks[j].text = convertHTMLToUnicode(dataTicks[j].text); From 5af1c6de613c5cb9b830d2eef964a2ae06f4d755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 10 Aug 2016 11:51:57 -0400 Subject: [PATCH 07/10] gl2d: don't require Plotly --- src/plots/gl2d/convert.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plots/gl2d/convert.js b/src/plots/gl2d/convert.js index 13f584a36d7..c84ba0cdfc6 100644 --- a/src/plots/gl2d/convert.js +++ b/src/plots/gl2d/convert.js @@ -9,7 +9,8 @@ 'use strict'; -var Plotly = require('../../plotly'); +var Plots = require('../plots'); +var Axes = require('../cartesian/axes'); var convertHTMLToUnicode = require('../../lib/html2unicode'); var str2RGBArray = require('../../lib/str2rgbarray'); @@ -180,8 +181,8 @@ proto.merge = function(options) { // is an axis shared with an already-drawn subplot ? proto.hasSharedAxis = function(ax) { var scene = this.scene, - subplotIds = Plotly.Plots.getSubplotIds(scene.fullLayout, 'gl2d'), - list = Plotly.Axes.findSubplotsWithAxis(subplotIds, ax); + subplotIds = Plots.getSubplotIds(scene.fullLayout, 'gl2d'), + list = Axes.findSubplotsWithAxis(subplotIds, ax); // if index === 0, then the subplot is already drawn as subplots // are drawn in order. From 5ee3c297983ad7be331dfff6908d49303979cc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 10 Aug 2016 12:28:04 -0400 Subject: [PATCH 08/10] polar (yes polar): rm circular dep patterns by: - removing add require('plotly'), - adding an index file, and - require the polar index in plot_api.js --- src/plot_api/plot_api.js | 5 +++-- src/plotly.js | 1 - src/plots/polar/index.js | 13 +++++++++++++ src/plots/polar/micropolar.js | 10 +++------- src/plots/polar/micropolar_manager.js | 20 +++++++++++--------- 5 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 src/plots/polar/index.js diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 5ce6953015f..ca9e51c9b81 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -20,6 +20,7 @@ var Queue = require('../lib/queue'); var Plots = require('../plots/plots'); var Fx = require('../plots/cartesian/graph_interact'); +var Polar = require('../plots/polar'); var Color = require('../components/color'); var Drawing = require('../components/drawing'); @@ -419,7 +420,7 @@ function plotPolar(gd, data, layout) { // fulfill gd requirements if(data) gd.data = data; if(layout) gd.layout = layout; - Plotly.micropolar.manager.fillLayout(gd); + Polar.manager.fillLayout(gd); if(gd._fullLayout.autosize === 'initial' && gd._context.autosizable) { plotAutoSize(gd, {}); @@ -432,7 +433,7 @@ function plotPolar(gd, data, layout) { }); // instantiate framework - gd.framework = Plotly.micropolar.manager.framework(gd); + gd.framework = Polar.manager.framework(gd); // plot gd.framework({data: gd.data, layout: gd.layout}, paperDiv.node()); diff --git a/src/plotly.js b/src/plotly.js index 0dd94594e2b..acd4581142b 100644 --- a/src/plotly.js +++ b/src/plotly.js @@ -38,7 +38,6 @@ var Plots = exports.Plots = require('./plots/plots'); exports.Axes = require('./plots/cartesian/axes'); exports.Fx = require('./plots/cartesian/graph_interact'); -exports.micropolar = require('./plots/polar/micropolar'); // components exports.Color = require('./components/color'); diff --git a/src/plots/polar/index.js b/src/plots/polar/index.js new file mode 100644 index 00000000000..72c527d87db --- /dev/null +++ b/src/plots/polar/index.js @@ -0,0 +1,13 @@ +/** +* Copyright 2012-2016, 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 Polar = module.exports = require('./micropolar'); + +Polar.manager = require('./micropolar_manager'); diff --git a/src/plots/polar/micropolar.js b/src/plots/polar/micropolar.js index a17a0cf3995..e3f425c7fe9 100644 --- a/src/plots/polar/micropolar.js +++ b/src/plots/polar/micropolar.js @@ -6,15 +6,11 @@ * LICENSE file in the root directory of this source tree. */ -var Plotly = require('../../plotly'); var d3 = require('d3'); +var Lib = require('../../lib'); +var extendDeepAll = Lib.extendDeepAll; -var µ = module.exports = { - version: '0.2.2', - manager: require('./micropolar_manager') -}; - -var extendDeepAll = Plotly.Lib.extendDeepAll; +var µ = module.exports = { version: '0.2.2' }; µ.Axis = function module() { var config = { diff --git a/src/plots/polar/micropolar_manager.js b/src/plots/polar/micropolar_manager.js index 2c9e3b37b45..8ca681c5297 100644 --- a/src/plots/polar/micropolar_manager.js +++ b/src/plots/polar/micropolar_manager.js @@ -9,14 +9,16 @@ 'use strict'; -var Plotly = require('../../plotly'); var d3 = require('d3'); +var Lib = require('../../lib'); +var Color = require('../../components/color'); + +var micropolar = require('./micropolar'); var UndoManager = require('./undo_manager'); +var extendDeepAll = Lib.extendDeepAll; var manager = module.exports = {}; -var extendDeepAll = Plotly.Lib.extendDeepAll; - manager.framework = function(_gd) { var config, previousConfigClone, plot, convertedInput, container; var undoManager = new UndoManager(); @@ -29,8 +31,8 @@ manager.framework = function(_gd) { _inputConfig : extendDeepAll(config, _inputConfig); - if(!plot) plot = Plotly.micropolar.Axis(); - convertedInput = Plotly.micropolar.adapter.plotly().convert(config); + if(!plot) plot = micropolar.Axis(); + convertedInput = micropolar.adapter.plotly().convert(config); plot.config(convertedInput).render(container); _gd.data = config.data; _gd.layout = config.layout; @@ -41,12 +43,12 @@ manager.framework = function(_gd) { exports.svg = function() { return plot.svg(); }; exports.getConfig = function() { return config; }; exports.getLiveConfig = function() { - return Plotly.micropolar.adapter.plotly().convert(plot.getLiveConfig(), true); + return micropolar.adapter.plotly().convert(plot.getLiveConfig(), true); }; exports.getLiveScales = function() { return {t: plot.angularScale(), r: plot.radialScale()}; }; exports.setUndoPoint = function() { var that = this; - var configClone = Plotly.micropolar.util.cloneJson(config); + var configClone = micropolar.util.cloneJson(config); (function(_configClone, _previousConfigClone) { undoManager.add({ undo: function() { @@ -57,7 +59,7 @@ manager.framework = function(_gd) { } }); })(configClone, previousConfigClone); - previousConfigClone = Plotly.micropolar.util.cloneJson(configClone); + previousConfigClone = micropolar.util.cloneJson(configClone); }; exports.undo = function() { undoManager.undo(); }; exports.redo = function() { undoManager.redo(); }; @@ -71,7 +73,7 @@ manager.fillLayout = function(_gd) { dflts = { width: 800, height: 600, - paper_bgcolor: Plotly.Color.background, + paper_bgcolor: Color.background, _container: container, _paperdiv: paperDiv, _paper: paper From 873f3ae4ce053a27e719ecfa0dfce9e963f0e9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 10 Aug 2016 16:20:44 -0400 Subject: [PATCH 09/10] lib: rm circular deps by: - not requiring Lib into plot_config.js to log error - rm useless Lib.log in lib/dates.js - require lib/loggers.js directly instead of Lib in lib/search.js --- src/lib/dates.js | 9 ++------- src/lib/loggers.js | 4 ++-- src/lib/search.js | 5 ++--- src/plot_api/plot_config.js | 10 +++++++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/lib/dates.js b/src/lib/dates.js index 1c4063f3823..d3779e90718 100644 --- a/src/lib/dates.js +++ b/src/lib/dates.js @@ -12,8 +12,6 @@ var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); -var Lib = require('../lib'); - /** * dateTime2ms - turn a date object or string s of the form @@ -123,14 +121,11 @@ function lpad(val, digits) { * If rng is big, the later parts of time will be omitted */ exports.ms2DateTime = function(ms, r) { - if(typeof(d3) === 'undefined') { - Lib.error('d3 is not defined.'); - return; - } - if(!r) r = 0; + var d = new Date(ms), s = d3.time.format('%Y-%m-%d')(d); + if(r < 7776000000) { // <90 days: add hours s += ' ' + lpad(d.getHours(), 2); diff --git a/src/lib/loggers.js b/src/lib/loggers.js index bfb479bae7c..048298964f6 100644 --- a/src/lib/loggers.js +++ b/src/lib/loggers.js @@ -8,6 +8,8 @@ 'use strict'; +/* eslint-disable no-console */ + var config = require('../plot_api/plot_config'); var loggers = module.exports = {}; @@ -18,7 +20,6 @@ var loggers = module.exports = {}; * ------------------------------------------ */ -/* eslint-disable no-console */ loggers.log = function() { if(config.logging > 1) { var messages = ['LOG:']; @@ -62,4 +63,3 @@ loggers.error = function() { console.error.apply(console, arguments); } }; -/* eslint-enable no-console */ diff --git a/src/lib/search.js b/src/lib/search.js index 6a7aadb26a5..1dcab13f3b6 100644 --- a/src/lib/search.js +++ b/src/lib/search.js @@ -10,8 +10,7 @@ 'use strict'; var isNumeric = require('fast-isnumeric'); - -var Lib = require('../lib'); +var loggers = require('./loggers'); /** @@ -47,7 +46,7 @@ exports.findBin = function(val, bins, linelow) { if(test(bins[n], val)) n1 = n + 1; else n2 = n; } - if(c > 90) Lib.log('Long binary search...'); + if(c > 90) loggers.log('Long binary search...'); return n1 - 1; } }; diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 8cd10023178..7214c28c60a 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -8,7 +8,7 @@ 'use strict'; -var Lib = require('../lib'); +/* eslint-disable no-console */ /** * This will be transferred over to gd and overridden by @@ -98,10 +98,14 @@ module.exports = { }; // where and how the background gets set can be overridden by context -// so we define the default (plotlyjs) behavior here +// so we define the default (plotly.js) behavior here function defaultSetBackground(gd, bgColor) { try { gd._fullLayout._paper.style('background', bgColor); } - catch(e) { Lib.error(e); } + catch(e) { + if(module.exports.logging > 0) { + console.error(e); + } + } } From 95e9259604f3a7709effe6e282af8d0426b4ebc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Wed, 10 Aug 2016 16:45:45 -0400 Subject: [PATCH 10/10] modebar: make module more consistent with other components by: - making modebar/index.js require what needs to be exposed for other parts of the code - in consequence old modebar/index.js -> modebar/modebar.js - var ModeBar = require('modebar/') and use ModeBar.manage in plot_api.js --- src/components/modebar/index.js | 278 +--------------------------- src/components/modebar/manage.js | 2 +- src/components/modebar/modebar.js | 288 +++++++++++++++++++++++++++++ src/plot_api/plot_api.js | 6 +- test/jasmine/tests/modebar_test.js | 2 +- 5 files changed, 294 insertions(+), 282 deletions(-) create mode 100644 src/components/modebar/modebar.js diff --git a/src/components/modebar/index.js b/src/components/modebar/index.js index 54f13f9172d..7a33d7e3a0c 100644 --- a/src/components/modebar/index.js +++ b/src/components/modebar/index.js @@ -9,280 +9,4 @@ 'use strict'; -var d3 = require('d3'); - -var Lib = require('../../lib'); -var Icons = require('../../../build/ploticon'); - - -/** - * UI controller for interactive plots - * @Class - * @Param {object} opts - * @Param {object} opts.buttons nested arrays of grouped buttons config objects - * @Param {object} opts.container container div to append modeBar - * @Param {object} opts.graphInfo primary plot object containing data and layout - */ -function ModeBar(opts) { - this.container = opts.container; - this.element = document.createElement('div'); - - this.update(opts.graphInfo, opts.buttons); - - this.container.appendChild(this.element); -} - -var proto = ModeBar.prototype; - -/** - * Update modeBar (buttons and logo) - * - * @param {object} graphInfo primary plot object containing data and layout - * @param {array of arrays} buttons nested arrays of grouped buttons to initialize - * - */ -proto.update = function(graphInfo, buttons) { - this.graphInfo = graphInfo; - - var context = this.graphInfo._context; - - if(context.displayModeBar === 'hover') { - this.element.className = 'modebar modebar--hover'; - } - else this.element.className = 'modebar'; - - // if buttons or logo have changed, redraw modebar interior - var needsNewButtons = !this.hasButtons(buttons), - needsNewLogo = (this.hasLogo !== context.displaylogo); - - if(needsNewButtons || needsNewLogo) { - this.removeAllButtons(); - - this.updateButtons(buttons); - - if(context.displaylogo) { - this.element.appendChild(this.getLogo()); - this.hasLogo = true; - } - } - - this.updateActiveButton(); -}; - -proto.updateButtons = function(buttons) { - var _this = this; - - this.buttons = buttons; - this.buttonElements = []; - this.buttonsNames = []; - - this.buttons.forEach(function(buttonGroup) { - var group = _this.createGroup(); - - buttonGroup.forEach(function(buttonConfig) { - var buttonName = buttonConfig.name; - if(!buttonName) { - throw new Error('must provide button \'name\' in button config'); - } - if(_this.buttonsNames.indexOf(buttonName) !== -1) { - throw new Error('button name \'' + buttonName + '\' is taken'); - } - _this.buttonsNames.push(buttonName); - - var button = _this.createButton(buttonConfig); - _this.buttonElements.push(button); - group.appendChild(button); - }); - - _this.element.appendChild(group); - }); -}; - -/** - * Empty div for containing a group of buttons - * @Return {HTMLelement} - */ -proto.createGroup = function() { - var group = document.createElement('div'); - group.className = 'modebar-group'; - - return group; -}; - -/** - * Create a new button div and set constant and configurable attributes - * @Param {object} config (see ./buttons.js for more info) - * @Return {HTMLelement} - */ -proto.createButton = function(config) { - var _this = this, - button = document.createElement('a'); - - button.setAttribute('rel', 'tooltip'); - button.className = 'modebar-btn'; - - var title = config.title; - if(title === undefined) title = config.name; - if(title || title === 0) button.setAttribute('data-title', title); - - if(config.attr !== undefined) button.setAttribute('data-attr', config.attr); - - var val = config.val; - if(val !== undefined) { - if(typeof val === 'function') val = val(this.graphInfo); - button.setAttribute('data-val', val); - } - - var click = config.click; - if(typeof click !== 'function') { - throw new Error('must provide button \'click\' function in button config'); - } - else { - button.addEventListener('click', function(ev) { - config.click(_this.graphInfo, ev); - - // only needed for 'hoverClosestGeo' which does not call relayout - _this.updateActiveButton(ev.currentTarget); - }); - } - - button.setAttribute('data-toggle', config.toggle || false); - if(config.toggle) button.classList.add('active'); - - button.appendChild(this.createIcon(config.icon || Icons.question)); - button.setAttribute('data-gravity', config.gravity || 'n'); - - return button; -}; - -/** - * Add an icon to a button - * @Param {object} thisIcon - * @Param {number} thisIcon.width - * @Param {string} thisIcon.path - * @Return {HTMLelement} - */ -proto.createIcon = function(thisIcon) { - var iconHeight = thisIcon.ascent - thisIcon.descent, - svgNS = 'http://www.w3.org/2000/svg', - icon = document.createElementNS(svgNS, 'svg'), - path = document.createElementNS(svgNS, 'path'); - - icon.setAttribute('height', '1em'); - icon.setAttribute('width', (thisIcon.width / iconHeight) + 'em'); - icon.setAttribute('viewBox', [0, 0, thisIcon.width, iconHeight].join(' ')); - - path.setAttribute('d', thisIcon.path); - path.setAttribute('transform', 'matrix(1 0 0 -1 0 ' + thisIcon.ascent + ')'); - icon.appendChild(path); - - return icon; -}; - -/** - * Updates active button with attribute specified in layout - * @Param {object} graphInfo plot object containing data and layout - * @Return {HTMLelement} - */ -proto.updateActiveButton = function(buttonClicked) { - var fullLayout = this.graphInfo._fullLayout, - dataAttrClicked = (buttonClicked !== undefined) ? - buttonClicked.getAttribute('data-attr') : - null; - - this.buttonElements.forEach(function(button) { - var thisval = button.getAttribute('data-val') || true, - dataAttr = button.getAttribute('data-attr'), - isToggleButton = (button.getAttribute('data-toggle') === 'true'), - button3 = d3.select(button); - - // Use 'data-toggle' and 'buttonClicked' to toggle buttons - // that have no one-to-one equivalent in fullLayout - if(isToggleButton) { - if(dataAttr === dataAttrClicked) { - button3.classed('active', !button3.classed('active')); - } - } - else { - var val = (dataAttr === null) ? - dataAttr : - Lib.nestedProperty(fullLayout, dataAttr).get(); - - button3.classed('active', val === thisval); - } - - }); -}; - -/** - * Check if modeBar is configured as button configuration argument - * - * @Param {object} buttons 2d array of grouped button config objects - * @Return {boolean} - */ -proto.hasButtons = function(buttons) { - var currentButtons = this.buttons; - - if(!currentButtons) return false; - - if(buttons.length !== currentButtons.length) return false; - - for(var i = 0; i < buttons.length; ++i) { - if(buttons[i].length !== currentButtons[i].length) return false; - for(var j = 0; j < buttons[i].length; j++) { - if(buttons[i][j].name !== currentButtons[i][j].name) return false; - } - } - - return true; -}; - -/** - * @return {HTMLDivElement} The logo image wrapped in a group - */ -proto.getLogo = function() { - var group = this.createGroup(), - a = document.createElement('a'); - - a.href = 'https://plot.ly/'; - a.target = '_blank'; - a.setAttribute('data-title', 'Produced with Plotly'); - a.className = 'modebar-btn plotlyjsicon modebar-btn--logo'; - - a.appendChild(this.createIcon(Icons.plotlylogo)); - - group.appendChild(a); - return group; -}; - -proto.removeAllButtons = function() { - while(this.element.firstChild) { - this.element.removeChild(this.element.firstChild); - } - - this.hasLogo = false; -}; - -proto.destroy = function() { - Lib.removeElement(this.container.querySelector('.modebar')); -}; - -function createModeBar(gd, buttons) { - var fullLayout = gd._fullLayout; - - var modeBar = new ModeBar({ - graphInfo: gd, - container: fullLayout._paperdiv.node(), - buttons: buttons - }); - - if(fullLayout._privateplot) { - d3.select(modeBar.element).append('span') - .classed('badge-private float--left', true) - .text('PRIVATE'); - } - - return modeBar; -} - -module.exports = createModeBar; +exports.manage = require('./manage'); diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 1ed905461fe..1f6c77ec496 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -12,7 +12,7 @@ var Axes = require('../../plots/cartesian/axes'); var scatterSubTypes = require('../../traces/scatter/subtypes'); -var createModeBar = require('./'); +var createModeBar = require('./modebar'); var modeBarButtons = require('./buttons'); /** diff --git a/src/components/modebar/modebar.js b/src/components/modebar/modebar.js new file mode 100644 index 00000000000..54f13f9172d --- /dev/null +++ b/src/components/modebar/modebar.js @@ -0,0 +1,288 @@ +/** +* Copyright 2012-2016, 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 d3 = require('d3'); + +var Lib = require('../../lib'); +var Icons = require('../../../build/ploticon'); + + +/** + * UI controller for interactive plots + * @Class + * @Param {object} opts + * @Param {object} opts.buttons nested arrays of grouped buttons config objects + * @Param {object} opts.container container div to append modeBar + * @Param {object} opts.graphInfo primary plot object containing data and layout + */ +function ModeBar(opts) { + this.container = opts.container; + this.element = document.createElement('div'); + + this.update(opts.graphInfo, opts.buttons); + + this.container.appendChild(this.element); +} + +var proto = ModeBar.prototype; + +/** + * Update modeBar (buttons and logo) + * + * @param {object} graphInfo primary plot object containing data and layout + * @param {array of arrays} buttons nested arrays of grouped buttons to initialize + * + */ +proto.update = function(graphInfo, buttons) { + this.graphInfo = graphInfo; + + var context = this.graphInfo._context; + + if(context.displayModeBar === 'hover') { + this.element.className = 'modebar modebar--hover'; + } + else this.element.className = 'modebar'; + + // if buttons or logo have changed, redraw modebar interior + var needsNewButtons = !this.hasButtons(buttons), + needsNewLogo = (this.hasLogo !== context.displaylogo); + + if(needsNewButtons || needsNewLogo) { + this.removeAllButtons(); + + this.updateButtons(buttons); + + if(context.displaylogo) { + this.element.appendChild(this.getLogo()); + this.hasLogo = true; + } + } + + this.updateActiveButton(); +}; + +proto.updateButtons = function(buttons) { + var _this = this; + + this.buttons = buttons; + this.buttonElements = []; + this.buttonsNames = []; + + this.buttons.forEach(function(buttonGroup) { + var group = _this.createGroup(); + + buttonGroup.forEach(function(buttonConfig) { + var buttonName = buttonConfig.name; + if(!buttonName) { + throw new Error('must provide button \'name\' in button config'); + } + if(_this.buttonsNames.indexOf(buttonName) !== -1) { + throw new Error('button name \'' + buttonName + '\' is taken'); + } + _this.buttonsNames.push(buttonName); + + var button = _this.createButton(buttonConfig); + _this.buttonElements.push(button); + group.appendChild(button); + }); + + _this.element.appendChild(group); + }); +}; + +/** + * Empty div for containing a group of buttons + * @Return {HTMLelement} + */ +proto.createGroup = function() { + var group = document.createElement('div'); + group.className = 'modebar-group'; + + return group; +}; + +/** + * Create a new button div and set constant and configurable attributes + * @Param {object} config (see ./buttons.js for more info) + * @Return {HTMLelement} + */ +proto.createButton = function(config) { + var _this = this, + button = document.createElement('a'); + + button.setAttribute('rel', 'tooltip'); + button.className = 'modebar-btn'; + + var title = config.title; + if(title === undefined) title = config.name; + if(title || title === 0) button.setAttribute('data-title', title); + + if(config.attr !== undefined) button.setAttribute('data-attr', config.attr); + + var val = config.val; + if(val !== undefined) { + if(typeof val === 'function') val = val(this.graphInfo); + button.setAttribute('data-val', val); + } + + var click = config.click; + if(typeof click !== 'function') { + throw new Error('must provide button \'click\' function in button config'); + } + else { + button.addEventListener('click', function(ev) { + config.click(_this.graphInfo, ev); + + // only needed for 'hoverClosestGeo' which does not call relayout + _this.updateActiveButton(ev.currentTarget); + }); + } + + button.setAttribute('data-toggle', config.toggle || false); + if(config.toggle) button.classList.add('active'); + + button.appendChild(this.createIcon(config.icon || Icons.question)); + button.setAttribute('data-gravity', config.gravity || 'n'); + + return button; +}; + +/** + * Add an icon to a button + * @Param {object} thisIcon + * @Param {number} thisIcon.width + * @Param {string} thisIcon.path + * @Return {HTMLelement} + */ +proto.createIcon = function(thisIcon) { + var iconHeight = thisIcon.ascent - thisIcon.descent, + svgNS = 'http://www.w3.org/2000/svg', + icon = document.createElementNS(svgNS, 'svg'), + path = document.createElementNS(svgNS, 'path'); + + icon.setAttribute('height', '1em'); + icon.setAttribute('width', (thisIcon.width / iconHeight) + 'em'); + icon.setAttribute('viewBox', [0, 0, thisIcon.width, iconHeight].join(' ')); + + path.setAttribute('d', thisIcon.path); + path.setAttribute('transform', 'matrix(1 0 0 -1 0 ' + thisIcon.ascent + ')'); + icon.appendChild(path); + + return icon; +}; + +/** + * Updates active button with attribute specified in layout + * @Param {object} graphInfo plot object containing data and layout + * @Return {HTMLelement} + */ +proto.updateActiveButton = function(buttonClicked) { + var fullLayout = this.graphInfo._fullLayout, + dataAttrClicked = (buttonClicked !== undefined) ? + buttonClicked.getAttribute('data-attr') : + null; + + this.buttonElements.forEach(function(button) { + var thisval = button.getAttribute('data-val') || true, + dataAttr = button.getAttribute('data-attr'), + isToggleButton = (button.getAttribute('data-toggle') === 'true'), + button3 = d3.select(button); + + // Use 'data-toggle' and 'buttonClicked' to toggle buttons + // that have no one-to-one equivalent in fullLayout + if(isToggleButton) { + if(dataAttr === dataAttrClicked) { + button3.classed('active', !button3.classed('active')); + } + } + else { + var val = (dataAttr === null) ? + dataAttr : + Lib.nestedProperty(fullLayout, dataAttr).get(); + + button3.classed('active', val === thisval); + } + + }); +}; + +/** + * Check if modeBar is configured as button configuration argument + * + * @Param {object} buttons 2d array of grouped button config objects + * @Return {boolean} + */ +proto.hasButtons = function(buttons) { + var currentButtons = this.buttons; + + if(!currentButtons) return false; + + if(buttons.length !== currentButtons.length) return false; + + for(var i = 0; i < buttons.length; ++i) { + if(buttons[i].length !== currentButtons[i].length) return false; + for(var j = 0; j < buttons[i].length; j++) { + if(buttons[i][j].name !== currentButtons[i][j].name) return false; + } + } + + return true; +}; + +/** + * @return {HTMLDivElement} The logo image wrapped in a group + */ +proto.getLogo = function() { + var group = this.createGroup(), + a = document.createElement('a'); + + a.href = 'https://plot.ly/'; + a.target = '_blank'; + a.setAttribute('data-title', 'Produced with Plotly'); + a.className = 'modebar-btn plotlyjsicon modebar-btn--logo'; + + a.appendChild(this.createIcon(Icons.plotlylogo)); + + group.appendChild(a); + return group; +}; + +proto.removeAllButtons = function() { + while(this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + + this.hasLogo = false; +}; + +proto.destroy = function() { + Lib.removeElement(this.container.querySelector('.modebar')); +}; + +function createModeBar(gd, buttons) { + var fullLayout = gd._fullLayout; + + var modeBar = new ModeBar({ + graphInfo: gd, + container: fullLayout._paperdiv.node(), + buttons: buttons + }); + + if(fullLayout._privateplot) { + d3.select(modeBar.element).append('span') + .classed('badge-private float--left', true) + .text('PRIVATE'); + } + + return modeBar; +} + +module.exports = createModeBar; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index ca9e51c9b81..10cd4054d42 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -32,7 +32,7 @@ var RangeSelector = require('../components/rangeselector'); var UpdateMenus = require('../components/updatemenus'); var Shapes = require('../components/shapes'); var Titles = require('../components/titles'); -var manageModeBar = require('../components/modebar/manage'); +var ModeBar = require('../components/modebar'); var xmlnsNamespaces = require('../constants/xmlns_namespaces'); @@ -2444,7 +2444,7 @@ Plotly.relayout = function relayout(gd, astr, val) { // this is decoupled enough it doesn't need async regardless if(domodebar) { var subplotIds; - manageModeBar(gd); + ModeBar.manage(gd); Plotly.Fx.supplyLayoutDefaults(gd.layout, fullLayout, gd._fullData); Plotly.Fx.init(gd); @@ -3093,7 +3093,7 @@ function lsInner(gd) { drawMainTitle(gd); - manageModeBar(gd); + ModeBar.manage(gd); return gd._promises.length && Promise.all(gd._promises); } diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 3c4c884169e..047312179de 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1,6 +1,6 @@ var d3 = require('d3'); -var createModeBar = require('@src/components/modebar'); +var createModeBar = require('@src/components/modebar/modebar'); var manageModeBar = require('@src/components/modebar/manage'); var Plotly = require('@lib/index');