Skip to content

Commit 9a79056

Browse files
authored
Merge pull request #2474 from plotly/perf-drawFramwork
Perf drawFramwork
2 parents 7316d98 + 50ab638 commit 9a79056

File tree

28 files changed

+444
-560
lines changed

28 files changed

+444
-560
lines changed

src/components/colorbar/draw.js

+15-14
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,21 @@ module.exports = function draw(gd, id) {
245245
cbAxisOut.setScale();
246246

247247
// now draw the elements
248-
var container = fullLayout._infolayer.selectAll('g.' + id).data([0]);
249-
container.enter().append('g').classed(id, true)
250-
.classed(cn.colorbar, true)
251-
.each(function() {
252-
var s = d3.select(this);
253-
s.append('rect').classed(cn.cbbg, true);
254-
s.append('g').classed(cn.cbfills, true);
255-
s.append('g').classed(cn.cblines, true);
256-
s.append('g').classed(cn.cbaxis, true).classed(cn.crisp, true);
257-
s.append('g').classed(cn.cbtitleunshift, true)
258-
.append('g').classed(cn.cbtitle, true);
259-
s.append('rect').classed(cn.cboutline, true);
260-
s.select('.cbtitle').datum(0);
261-
});
248+
var container = Lib.ensureSingle(fullLayout._infolayer, 'g', id, function(s) {
249+
s.classed(cn.colorbar, true)
250+
.each(function() {
251+
var s = d3.select(this);
252+
s.append('rect').classed(cn.cbbg, true);
253+
s.append('g').classed(cn.cbfills, true);
254+
s.append('g').classed(cn.cblines, true);
255+
s.append('g').classed(cn.cbaxis, true).classed(cn.crisp, true);
256+
s.append('g').classed(cn.cbtitleunshift, true)
257+
.append('g').classed(cn.cbtitle, true);
258+
s.append('rect').classed(cn.cboutline, true);
259+
s.select('.cbtitle').datum(0);
260+
});
261+
});
262+
262263
container.attr('transform', 'translate(' + Math.round(gs.l) +
263264
',' + Math.round(gs.t) + ')');
264265
// TODO: this opposite transform is a hack until we make it

src/components/drawing/index.js

+31-32
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,7 @@ drawing.gradient = function(sel, gd, gradientID, type, color1, color2) {
415415
* The upside of this is arbitrary points can share gradient defs
416416
*/
417417
drawing.initGradients = function(gd) {
418-
var gradientsGroup = gd._fullLayout._defs.selectAll('.gradients').data([0]);
419-
gradientsGroup.enter().append('g').classed('gradients', true);
420-
418+
var gradientsGroup = Lib.ensureSingle(gd._fullLayout._defs, 'g', 'gradients');
421419
gradientsGroup.selectAll('linearGradient,radialGradient').remove();
422420
};
423421

@@ -729,33 +727,28 @@ drawing.steps = function(shape) {
729727
// off-screen svg render testing element, shared by the whole page
730728
// uses the id 'js-plotly-tester' and stores it in drawing.tester
731729
drawing.makeTester = function() {
732-
var tester = d3.select('body')
733-
.selectAll('#js-plotly-tester')
734-
.data([0]);
735-
736-
tester.enter().append('svg')
737-
.attr('id', 'js-plotly-tester')
738-
.attr(xmlnsNamespaces.svgAttrs)
739-
.style({
740-
position: 'absolute',
741-
left: '-10000px',
742-
top: '-10000px',
743-
width: '9000px',
744-
height: '9000px',
745-
'z-index': '1'
746-
});
730+
var tester = Lib.ensureSingleById(d3.select('body'), 'svg', 'js-plotly-tester', function(s) {
731+
s.attr(xmlnsNamespaces.svgAttrs)
732+
.style({
733+
position: 'absolute',
734+
left: '-10000px',
735+
top: '-10000px',
736+
width: '9000px',
737+
height: '9000px',
738+
'z-index': '1'
739+
});
740+
});
747741

748742
// browsers differ on how they describe the bounding rect of
749743
// the svg if its contents spill over... so make a 1x1px
750744
// reference point we can measure off of.
751-
var testref = tester.selectAll('.js-reference-point').data([0]);
752-
testref.enter().append('path')
753-
.classed('js-reference-point', true)
754-
.attr('d', 'M0,0H1V1H0Z')
755-
.style({
756-
'stroke-width': 0,
757-
fill: 'black'
758-
});
745+
var testref = Lib.ensureSingle(tester, 'path', 'js-reference-point', function(s) {
746+
s.attr('d', 'M0,0H1V1H0Z')
747+
.style({
748+
'stroke-width': 0,
749+
fill: 'black'
750+
});
751+
});
759752

760753
drawing.tester = tester;
761754
drawing.testref = testref;
@@ -917,15 +910,21 @@ drawing.setClipUrl = function(s, localId) {
917910
return;
918911
}
919912

920-
var url = '#' + localId,
921-
base = d3.select('base');
913+
if(drawing.baseUrl === undefined) {
914+
var base = d3.select('base');
922915

923-
// add id to location href w/o hashes if any)
924-
if(base.size() && base.attr('href')) {
925-
url = window.location.href.split('#')[0] + url;
916+
// Stash base url once and for all!
917+
// We may have to stash this elsewhere when
918+
// we'll try to support for child windows
919+
// more info -> https://github.com/plotly/plotly.js/issues/702
920+
if(base.size() && base.attr('href')) {
921+
drawing.baseUrl = window.location.href.split('#')[0];
922+
} else {
923+
drawing.baseUrl = '';
924+
}
926925
}
927926

928-
s.attr('clip-path', 'url(' + url + ')');
927+
s.attr('clip-path', 'url(' + drawing.baseUrl + '#' + localId + ')');
929928
};
930929

931930
drawing.getTranslate = function(element) {

src/components/fx/hover.js

+9-11
Original file line numberDiff line numberDiff line change
@@ -696,23 +696,21 @@ function createHoverText(hoverData, opts, gd) {
696696
commonLabel.exit().remove();
697697

698698
commonLabel.each(function() {
699-
var label = d3.select(this),
700-
lpath = label.selectAll('path').data([0]),
701-
ltext = label.selectAll('text').data([0]);
702-
703-
lpath.enter().append('path')
704-
.style({'stroke-width': '1px'});
699+
var label = d3.select(this);
700+
var lpath = Lib.ensureSingle(label, 'path', '', function(s) {
701+
s.style({'stroke-width': '1px'});
702+
});
703+
var ltext = Lib.ensureSingle(label, 'text', '', function(s) {
704+
// prohibit tex interpretation until we can handle
705+
// tex and regular text together
706+
s.attr('data-notex', 1);
707+
});
705708

706709
lpath.style({
707710
fill: commonLabelOpts.bgcolor || Color.defaultLine,
708711
stroke: commonLabelOpts.bordercolor || Color.background,
709712
});
710713

711-
ltext.enter().append('text')
712-
// prohibit tex interpretation until we can handle
713-
// tex and regular text together
714-
.attr('data-notex', 1);
715-
716714
ltext.text(t0)
717715
.call(Drawing.font,
718716
commonLabelOpts.font.family || fontFamily,

src/components/legend/draw.js

+20-45
Original file line numberDiff line numberDiff line change
@@ -53,52 +53,35 @@ module.exports = function draw(gd) {
5353
return;
5454
}
5555

56-
var legend = fullLayout._infolayer.selectAll('g.legend')
57-
.data([0]);
58-
59-
legend.enter().append('g')
60-
.attr({
61-
'class': 'legend',
62-
'pointer-events': 'all'
63-
});
64-
65-
var clipPath = fullLayout._topdefs.selectAll('#' + clipId)
66-
.data([0]);
67-
68-
clipPath.enter().append('clipPath')
69-
.attr('id', clipId)
70-
.append('rect');
56+
var firstRender = false;
57+
var legend = Lib.ensureSingle(fullLayout._infolayer, 'g', 'legend', function(s) {
58+
s.attr('pointer-events', 'all');
59+
firstRender = true;
60+
});
7161

72-
var bg = legend.selectAll('rect.bg')
73-
.data([0]);
62+
var clipPath = Lib.ensureSingleById(fullLayout._topdefs, 'clipPath', clipId, function(s) {
63+
s.append('rect');
64+
});
7465

75-
bg.enter().append('rect').attr({
76-
'class': 'bg',
77-
'shape-rendering': 'crispEdges'
66+
var bg = Lib.ensureSingle(legend, 'rect', 'bg', function(s) {
67+
s.attr('shape-rendering', 'crispEdges');
7868
});
7969

8070
bg.call(Color.stroke, opts.bordercolor)
8171
.call(Color.fill, opts.bgcolor)
8272
.style('stroke-width', opts.borderwidth + 'px');
8373

84-
var scrollBox = legend.selectAll('g.scrollbox')
85-
.data([0]);
86-
87-
scrollBox.enter().append('g')
88-
.attr('class', 'scrollbox');
74+
var scrollBox = Lib.ensureSingle(legend, 'g', 'scrollbox');
8975

90-
var scrollBar = legend.selectAll('rect.scrollbar')
91-
.data([0]);
92-
93-
scrollBar.enter().append('rect')
94-
.attr({
95-
'class': 'scrollbar',
76+
var scrollBar = Lib.ensureSingle(legend, 'rect', 'scrollbar', function(s) {
77+
s.attr({
9678
rx: 20,
9779
ry: 3,
9880
width: 0,
9981
height: 0
10082
})
10183
.call(Color.fill, '#808BA4');
84+
});
10285

10386
var groups = scrollBox.selectAll('g.groups')
10487
.data(legendData);
@@ -129,7 +112,6 @@ module.exports = function draw(gd) {
129112
.call(setupTraceToggle, gd);
130113
});
131114

132-
var firstRender = legend.enter().size() !== 0;
133115
if(firstRender) {
134116
computeLegendDimensions(gd, groups, traces);
135117
expandMargin(gd);
@@ -378,10 +360,7 @@ function drawTexts(g, gd) {
378360
traceIndex = trace.index,
379361
name = isPie ? legendItem.label : trace.name;
380362

381-
var text = g.selectAll('text.legendtext')
382-
.data([0]);
383-
384-
text.enter().append('text').classed('legendtext', true);
363+
var text = Lib.ensureSingle(g, 'text', 'legendtext');
385364

386365
text.attr('text-anchor', 'start')
387366
.classed('user-select-none', true)
@@ -446,15 +425,11 @@ function setupTraceToggle(g, gd) {
446425
var newMouseDownTime,
447426
numClicks = 1;
448427

449-
var traceToggle = g.selectAll('rect')
450-
.data([0]);
451-
452-
traceToggle.enter().append('rect')
453-
.classed('legendtoggle', true)
454-
.style('cursor', 'pointer')
455-
.attr('pointer-events', 'all')
456-
.call(Color.fill, 'rgba(0,0,0,0)');
457-
428+
var traceToggle = Lib.ensureSingle(g, 'rect', 'legendtoggle', function(s) {
429+
s.style('cursor', 'pointer')
430+
.attr('pointer-events', 'all')
431+
.call(Color.fill, 'rgba(0,0,0,0)');
432+
});
458433

459434
traceToggle.on('mousedown', function() {
460435
newMouseDownTime = (new Date()).getTime();

src/components/legend/style.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var d3 = require('d3');
@@ -19,15 +18,11 @@ var Color = require('../color');
1918
var subTypes = require('../../traces/scatter/subtypes');
2019
var stylePie = require('../../traces/pie/style_one');
2120

22-
2321
module.exports = function style(s, gd) {
2422
s.each(function(d) {
2523
var traceGroup = d3.select(this);
2624

27-
var layers = traceGroup.selectAll('g.layers')
28-
.data([0]);
29-
layers.enter().append('g')
30-
.classed('layers', true);
25+
var layers = Lib.ensureSingle(traceGroup, 'g', 'layers');
3126
layers.style('opacity', d[0].trace.opacity);
3227

3328
var fill = layers

src/components/rangeselector/draw.js

+8-15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var Registry = require('../../registry');
1414
var Plots = require('../../plots/plots');
1515
var Color = require('../color');
1616
var Drawing = require('../drawing');
17+
var Lib = require('../../lib');
1718
var svgTextUtils = require('../../lib/svg_text_utils');
1819
var axisIds = require('../../plots/cartesian/axis_ids');
1920
var anchorUtils = require('../legend/anchor_utils');
@@ -121,13 +122,9 @@ function isActive(axisLayout, opts, update) {
121122
}
122123

123124
function drawButtonRect(button, selectorLayout, d) {
124-
var rect = button.selectAll('rect')
125-
.data([0]);
126-
127-
rect.enter().append('rect')
128-
.classed('selector-rect', true);
129-
130-
rect.attr('shape-rendering', 'crispEdges');
125+
var rect = Lib.ensureSingle(button, 'rect', 'selector-rect', function(s) {
126+
s.attr('shape-rendering', 'crispEdges');
127+
});
131128

132129
rect.attr({
133130
'rx': constants.rx,
@@ -150,14 +147,10 @@ function drawButtonText(button, selectorLayout, d, gd) {
150147
svgTextUtils.convertToTspans(s, gd);
151148
}
152149

153-
var text = button.selectAll('text')
154-
.data([0]);
155-
156-
text.enter().append('text')
157-
.classed('selector-text', true)
158-
.classed('user-select-none', true);
159-
160-
text.attr('text-anchor', 'middle');
150+
var text = Lib.ensureSingle(button, 'text', 'selector-text', function(s) {
151+
s.classed('user-select-none', true)
152+
.attr('text-anchor', 'middle');
153+
});
161154

162155
text.call(Drawing.font, selectorLayout.font)
163156
.text(getLabel(d))

0 commit comments

Comments
 (0)