Skip to content

Expose Plotly.purge method #300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 11, 2016
21 changes: 10 additions & 11 deletions devtools/test_dashboard/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

var Lib = require('@src/lib');

var plotlist = document.getElementById('plot-list');
var plotList = document.getElementById('plot-list');
var anchor = document.getElementById('embedded-graph');
var image = document.getElementById('embedded-image');

Expand All @@ -14,31 +14,30 @@ anchor.style.height = '600px';
anchor.style.width = '1000px';

function plotButtons(plots, figDir) {

Object.keys(plots).forEach(function(plotname) {

var button = document.createElement('button');

button.style.cssFloat = 'left';
button.style.width = '100px';
button.style.height = '40px';

button.innerHTML = plotname;

plotlist.appendChild(button);
plotList.appendChild(button);

button.addEventListener('click', function() {

var myImage = new Image();
myImage.src = figDir + plotname + '.png';

image.innerHTML = '';
image.appendChild(myImage);


anchor.innerHTML = '';
var currentGraphDiv = Tabs.getGraph();
if(currentGraphDiv) Plotly.purge(currentGraphDiv);

gd = document.createElement('div');
gd.id = 'graph';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdtusz not sure why I didn't do this before, now you can use Plotly.plot('graph', [], {}) in the test-dashboard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍻


anchor.innerHTML = '';
anchor.appendChild(gd);

var plot = plots[plotname];
Expand All @@ -58,7 +57,7 @@ function plotButtons(plots, figDir) {
snapshot.innerHTML = 'snapshot';
snapshot.style.background = 'blue';

plotlist.appendChild(snapshot);
plotList.appendChild(snapshot);

snapshot.addEventListener('click', function() {

Expand Down Expand Up @@ -111,7 +110,7 @@ function plotButtons(plots, figDir) {
pummelButton.style.marginLeft = '25px';
pummelButton.innerHTML = 'pummel3d';
pummelButton.style.background = 'blue';
plotlist.appendChild(pummelButton);
plotList.appendChild(pummelButton);

var i = 0;
var mock = require('@mocks/gl3d_marker-color.json');
Expand Down Expand Up @@ -147,7 +146,7 @@ function plotButtons(plots, figDir) {
scrapeButton.style.marginLeft = '25px';
scrapeButton.innerHTML = 'scrape SVG';
scrapeButton.style.background = 'blue';
plotlist.appendChild(scrapeButton);
plotList.appendChild(scrapeButton);

scrapeButton.addEventListener('click', function() {
Plotly.Snapshot.toSVG(Tabs.get());
Expand Down
2 changes: 2 additions & 0 deletions devtools/test_dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
getGraph: function() {
return document.getElementById('embedded-graph').children[0];
},

fresh: function() {
var anchor = document.getElementById('embedded-graph'),
graphDiv = Tabs.getGraph();
Expand All @@ -37,6 +38,7 @@

return graphDiv;
},

plotMock: function(mockName) {
var mockURL = '../../test/image/mocks/' + mockName + '.json';

Expand Down
1 change: 1 addition & 0 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ exports.prependTraces = Plotly.prependTraces;
exports.addTraces = Plotly.addTraces;
exports.deleteTraces = Plotly.deleteTraces;
exports.moveTraces = Plotly.moveTraces;
exports.purge = Plotly.purge;
exports.setPlotConfig = require('./plot_api/set_plot_config');
exports.register = Plotly.register;

Expand Down
12 changes: 12 additions & 0 deletions src/lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,19 @@ var Events = {
*/
return jQueryHandlerValue !== undefined ? jQueryHandlerValue :
nodeEventHandlerValue;
},

purge: function(plotObj) {
delete plotObj._ev;
delete plotObj.on;
delete plotObj.once;
delete plotObj.removeListener;
delete plotObj.removeAllListeners;
delete plotObj.emit;

return plotObj;
}

};

module.exports = Events;
35 changes: 34 additions & 1 deletion src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2406,6 +2406,39 @@ Plotly.relayout = function relayout(gd, astr, val) {
});
};

/**
* Purge a graph container div back to its initial pre-Plotly.plot state
*
* @param {string id or DOM element} gd
* the id or DOM element of the graph container div
*/
Plotly.purge = function purge(gd) {
gd = getGraphDiv(gd);

var fullLayout = gd._fullLayout || {},
fullData = gd._fullData || [];

// remove gl contexts
Plots.cleanPlot([], {}, fullData, fullLayout);

// purge properties
Plots.purge(gd);

// purge event emitter methods
Events.purge(gd);

// remove plot container
if(fullLayout._container) fullLayout._container.remove();

delete gd._context;
delete gd._replotPending;
delete gd._mouseDownTime;
delete gd._hmpixcount;
delete gd._hmlumcount;

return gd;
};

/**
* Reduce all reserved margin objects to a single required margin reservation.
*
Expand Down Expand Up @@ -2505,7 +2538,7 @@ function makePlotFramework(gd) {
// Make the svg container
fullLayout._paperdiv = fullLayout._container.selectAll('.svg-container').data([0]);
fullLayout._paperdiv.enter().append('div')
.classed('svg-container',true)
.classed('svg-container', true)
.style('position','relative');

// Initial autosize
Expand Down
14 changes: 14 additions & 0 deletions src/plots/gl2d/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,17 @@ exports.plot = function plotGl2d(gd) {
scene.plot(fullSubplotData, fullLayout, gd.layout);
}
};

exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
var oldSceneKeys = Plots.getSubplotIds(oldFullLayout, 'gl2d');

for(var i = 0; i < oldSceneKeys.length; i++) {
var oldSubplot = oldFullLayout._plots[oldSceneKeys[i]],
xaName = oldSubplot.xaxis._name,
yaName = oldSubplot.yaxis._name;

if(!!oldSubplot._scene2d && (!newFullLayout[xaName] || !newFullLayout[yaName])) {
oldSubplot._scene2d.destroy();
}
}
};
8 changes: 8 additions & 0 deletions src/plots/gl2d/scene2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,13 @@ proto.cameraChanged = function() {

proto.destroy = function() {
this.glplot.dispose();

this.container.removeChild(this.canvas);
this.container.removeChild(this.svgContainer);
this.container.removeChild(this.mouseContainer);

this.glplot = null;
this.stopped = true;
};

proto.plot = function(fullData, fullLayout) {
Expand Down Expand Up @@ -405,6 +412,7 @@ proto.plot = function(fullData, fullLayout) {

proto.draw = function() {
if(this.stopped) return;

requestAnimationFrame(this.redraw);

var glplot = this.glplot,
Expand Down
13 changes: 5 additions & 8 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ plots.supplyDefaults = function(gd) {
plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData);

// clean subplots and other artifacts from previous plot calls
cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout);
plots.cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout);

/*
* Relink functions and underscore attributes to promote consistency between
Expand Down Expand Up @@ -520,7 +520,7 @@ plots.supplyDefaults = function(gd) {
}
};

function cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
var i, j;

var plotTypes = Object.keys(subplotsRegistry);
Expand Down Expand Up @@ -560,7 +560,7 @@ function cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout) {
oldFullLayout._infolayer.selectAll('.cb' + oldUid).remove();
}
}
}
};

/**
* Relink private _keys and keys with a function value from one layout
Expand Down Expand Up @@ -755,16 +755,13 @@ plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData) {
}
};

// Remove all plotly attributes from a div so it can be replotted fresh
// TODO: these really need to be encapsulated into a much smaller set...
plots.purge = function(gd) {
// remove all plotly attributes from a div so it can be replotted fresh
// TODO: these really need to be encapsulated into a much smaller set...

// note: we DO NOT remove _context because it doesn't change when we insert
// a new plot, and may have been set outside of our scope.

// clean up the gl and geo containers
// TODO unify subplot creation/update with d3.selection.order
// and/or subplot ids
var fullLayout = gd._fullLayout || {};
if(fullLayout._glcontainer !== undefined) fullLayout._glcontainer.remove();
if(fullLayout._geocontainer !== undefined) fullLayout._geocontainer.remove();
Expand Down
7 changes: 7 additions & 0 deletions test/jasmine/tests/events_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,15 @@ describe('Events', function() {
expect(eventBaton).toBe(3);
expect(result).toBe('pong');
});
});

describe('purge', function() {
it('should remove all method from the plotObj', function() {
Events.init(plotObj);
Events.purge(plotObj);

expect(plotObj).toEqual({});
});
});

});
50 changes: 47 additions & 3 deletions test/jasmine/tests/gl_plot_interact_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,19 @@ describe('Test gl plot interactions', function() {

sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d');
sceneIds.forEach(function(id) {
fullLayout[id]._scene.destroy();
var scene = fullLayout[id]._scene;

if(scene.glplot) scene.destroy();
});

sceneIds = Plots.getSubplotIds(fullLayout, 'gl2d');
sceneIds.forEach(function(id) {
var scene2d = fullLayout._plots[id]._scene2d;
scene2d.stopped = true;
scene2d.destroy();

if(scene2d.glplot) {
scene2d.stopped = true;
scene2d.destroy();
}
});

destroyGraphDiv();
Expand Down Expand Up @@ -369,4 +374,43 @@ describe('Test gl plot interactions', function() {
});

});

describe('Plots.cleanPlot', function() {

it('should remove gl context from the graph div of a gl3d plot', function(done) {
gd = createGraphDiv();

var mockData = [{
type: 'scatter3d'
}];

Plotly.plot(gd, mockData).then(function() {
expect(gd._fullLayout.scene._scene.glplot).toBeDefined();

Plots.cleanPlot([], {}, gd._fullData, gd._fullLayout);
expect(gd._fullLayout.scene._scene.glplot).toBe(null);

done();
});
});

it('should remove gl context from the graph div of a gl2d plot', function(done) {
gd = createGraphDiv();

var mockData = [{
type: 'scattergl',
x: [1,2,3],
y: [1,2,3]
}];

Plotly.plot(gd, mockData).then(function() {
expect(gd._fullLayout._plots.xy._scene2d.glplot).toBeDefined();

Plots.cleanPlot([], {}, gd._fullData, gd._fullLayout);
expect(gd._fullLayout._plots.xy._scene2d.glplot).toBe(null);

done();
});
});
});
});
21 changes: 21 additions & 0 deletions test/jasmine/tests/plot_api_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,27 @@ describe('Test plot api', function() {
});
});

describe('Plotly.purge', function() {

afterEach(destroyGraphDiv);

it('should return the graph div in its original state', function(done) {
var gd = createGraphDiv();
var initialKeys = Object.keys(gd);
var intialHTML = gd.innerHTML;
var mockData = [{ x: [1,2,3], y: [2,3,4] }];

Plotly.plot(gd, mockData).then(function() {
Plotly.purge(gd);

expect(Object.keys(gd)).toEqual(initialKeys);
expect(gd.innerHTML).toEqual(intialHTML);

done();
});
});
});

describe('cleanData', function() {
var gd;

Expand Down