Skip to content

Commit 47cf7e2

Browse files
committed
Make fast batch rendering
1 parent 6def5e4 commit 47cf7e2

File tree

2 files changed

+114
-67
lines changed

2 files changed

+114
-67
lines changed

src/traces/scattergl/convert.js

Lines changed: 100 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -98,74 +98,137 @@ function convertStyle(gd, trace) {
9898
}
9999

100100
function convertTextfont(trace, textfont) {
101-
var opts = [], i;
101+
var textOptions = {}, i;
102102

103-
for(i = 0; i < trace.text.length; i++) {
104-
var textOptions = opts[i] = {};
103+
textOptions.color = textfont.color;
105104

106-
textOptions.color = unarr(textfont.color, i);
105+
textOptions.align = [];
106+
textOptions.baseline = [];
107+
108+
var textposition = Array.isArray(trace.textposition) ? trace.textposition : [trace.textposition];
109+
110+
for(i = 0.0; i < textposition.length; i++) {
111+
var textpos = textposition[i].split(/\s+/);
107112

108-
var textpos = unarr(trace.textposition, i);
109-
textpos = textpos.split(/\s+/);
110113
switch(textpos[1]) {
111114
case 'left':
112-
textOptions.align = 'right';
115+
textOptions.align.push('right');
113116
break;
114117
case 'right':
115-
textOptions.align = 'left';
118+
textOptions.align.push('left');
116119
break;
117120
default:
118-
textOptions.align = textpos[1];
121+
textOptions.align.push(textpos[1]);
119122
}
120123

121124
switch(textpos[0]) {
122125
case 'top':
123-
textOptions.baseline = 'bottom';
126+
textOptions.baseline.push('bottom');
124127
break;
125128
case 'bottom':
126-
textOptions.baseline = 'top';
129+
textOptions.baseline.push('top');
127130
break;
128131
default:
129-
textOptions.baseline = textpos[0];
132+
textOptions.baseline.push(textpos[0]);
130133
}
134+
}
131135

132-
textfont = unarr(textfont, i);
133-
134-
var fontSize = unarr(textfont.size, i);
135-
136-
if(!isNumeric(fontSize)) {
137-
continue;
136+
// [{family, color, size}, {family, color, size}, ...] →
137+
// {family: [], color: [], size: []}
138+
if(Array.isArray(textfont)) {
139+
textOptions.font = [];
140+
textOptions.color = [];
141+
for(i = 0; i < textfont.length; i++) {
142+
textOptions.font.push({
143+
family: textfont[i].family,
144+
size: textfont[i].size
145+
});
146+
textOptions.color.push(textfont[i].color);
138147
}
148+
}
149+
else {
150+
// if any textfont param is array - make render a batch
151+
if(Array.isArray(textfont.family) || Array.isArray(textfont.size)) {
152+
textOptions.font = Array(Math.max(
153+
textfont.family && textfont.family.length || 1,
154+
textfont.size && textfont.size.length || 1
155+
));
156+
157+
for(i = 0; i < textOptions.font.length; i++) {
158+
textOptions.font[i] = {
159+
family: textfont.family[i] || textfont.family,
160+
size: textfont.size[i] || textfont.size
161+
};
162+
}
163+
}
164+
// if both are single values, make render fast single-value
165+
else {
166+
textOptions.font = {
167+
family: textfont.family,
168+
size: textfont.size
169+
};
170+
}
171+
textOptions.color = textfont.color;
172+
}
139173

140-
textOptions.font = {
141-
family: unarr(textfont.family, i),
142-
size: fontSize
143-
};
174+
// corresponds to textPointPosition from component.drawing
175+
if(trace.marker) {
176+
var sizes = [];
177+
if(Array.isArray(trace.marker.size)) {
178+
for(i = 0; i < trace.marker.size.length; i++) {
179+
sizes.push(trace.marker.size[i]);
180+
}
181+
}
182+
else if(Array.isArray(trace.marker)) {
183+
for(i = 0; i < trace.marker.length; i++) {
184+
sizes.push(trace.marker[i].size);
185+
}
186+
}
187+
else {
188+
sizes.push(trace.marker.size);
189+
}
144190

145-
// corresponds to textPointPosition from component.drawing
146-
if(trace.marker) {
147-
var hSign = TEXTOFFSETSIGN[textOptions.align];
148-
var markerRadius = unarr(unarr(trace.marker, i).size, i) / 2;
191+
textOptions.offset = [];
192+
for(i = 0; i < Math.max(trace.x.length, trace.y.length); i++) {
193+
var size = sizes.length > 1 ? sizes[i] : sizes[0];
194+
var markerRadius = size / 2;
195+
var fontSize = Array.isArray(textOptions.font) ? textOptions.font[i].size : textOptions.font.size;
196+
var align = Array.isArray(textOptions.align) ? textOptions.align[i] : textOptions.align;
197+
var baseline = Array.isArray(textOptions.baseline) ? textOptions.baseline[i] : textOptions.baseline;
198+
var hSign = TEXTOFFSETSIGN[align];
199+
var vSign = TEXTOFFSETSIGN[baseline];
149200
var xPad = markerRadius ? markerRadius / 0.8 + 1 : 0;
150-
var vSign = TEXTOFFSETSIGN[textOptions.baseline];
151201
var yPad = - vSign * xPad - vSign * 0.5;
152-
textOptions.offset = [hSign * xPad / fontSize, yPad / fontSize];
153-
}
154202

155-
textOptions.position = [unarr(trace.x, i), unarr(trace.y, i)];
203+
textOptions.offset.push(
204+
[hSign * xPad / fontSize, yPad / fontSize]
205+
);
206+
}
207+
}
156208

157-
textOptions.text = unarr(trace.text, i);
209+
textOptions.position = [];
210+
for(i = 0; i < trace.x.length; i++) {
211+
textOptions.position.push(trace.x[i], trace.y[i]);
212+
}
213+
textOptions.text = trace.text;
158214

215+
// filter out bad font sizes
216+
if(Array.isArray(textOptions.font)) {
217+
for(i = 0; i < textOptions.font.length; i++) {
218+
if(!isNumeric(textOptions.font[i].size)) {
219+
textOptions.font[i].size = 0;
220+
}
221+
}
222+
}
223+
else {
224+
if(!isNumeric(textOptions.font.size)) {
225+
textOptions.font.size = 0;
226+
}
159227
}
160228

161-
return opts;
229+
return textOptions;
162230
}
163231

164-
// FIXME: find proper util method for this
165-
function unarr(obj, i) {
166-
if(Array.isArray(obj)) return obj[i];
167-
return obj;
168-
}
169232

170233
function convertMarkerStyle(trace) {
171234
var count = trace._length;

src/traces/scattergl/index.js

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var createLine = require('regl-line2d');
1313
var createError = require('regl-error2d');
1414
var cluster = require('point-cluster');
1515
var arrayRange = require('array-range');
16-
var Text = require('../../../../gl-text/index');
16+
var Text = require('gl-text');
1717

1818
var Registry = require('../../registry');
1919
var Lib = require('../../lib');
@@ -210,7 +210,7 @@ function sceneUpdate(gd, subplot) {
210210

211211
// apply new option to all regl components (used on drag)
212212
scene.update = function update(opt) {
213-
var i, j;
213+
var i;
214214
var opts = new Array(scene.count);
215215
for(i = 0; i < scene.count; i++) {
216216
opts[i] = opt;
@@ -222,9 +222,7 @@ function sceneUpdate(gd, subplot) {
222222
if(scene.select2d) scene.select2d.update(opts);
223223
if(scene.glText) {
224224
for(i = 0; i < scene.glText.length; i++) {
225-
for(j = 0; j < scene.glText[i].length; j++) {
226-
scene.glText[i][j].update(opts[i]);
227-
}
225+
scene.glText[i].update(opts[i]);
228226
}
229227
}
230228

@@ -263,10 +261,8 @@ function sceneUpdate(gd, subplot) {
263261
}
264262

265263
if(scene.glText.length) {
266-
scene.glText.forEach(function(items) {
267-
items.forEach(function(item) {
268-
item.render();
269-
});
264+
scene.glText.forEach(function(text) {
265+
text.render();
270266
});
271267
}
272268

@@ -316,10 +312,8 @@ function sceneUpdate(gd, subplot) {
316312
if(scene.line2d) scene.line2d.destroy();
317313
if(scene.select2d) scene.select2d.destroy();
318314
if(scene.glText) {
319-
scene.glText.forEach(function(items) {
320-
items.forEach(function(item) {
321-
item.destroy();
322-
});
315+
scene.glText.forEach(function(text) {
316+
text.destroy();
323317
});
324318
}
325319

@@ -352,7 +346,7 @@ function sceneUpdate(gd, subplot) {
352346
function plot(gd, subplot, cdata) {
353347
if(!cdata.length) return;
354348

355-
var i, j, items, textOptions;
349+
var i;
356350

357351
var fullLayout = gd._fullLayout;
358352
var scene = cdata[0][0].t._scene;
@@ -393,22 +387,14 @@ function plot(gd, subplot, cdata) {
393387
if(scene.glText === true) {
394388
scene.glText = [];
395389
for(i = 0; i < scene.textOptions.length; i++) {
396-
textOptions = scene.textOptions[i];
397-
items = [];
398-
for(j = 0; j < textOptions.length; j++) {
399-
items.push(new Text(regl));
400-
}
401-
scene.glText[i] = items;
390+
scene.glText[i] = new Text(regl);
402391
}
403392
}
404393

405394
// update main marker options
406395
if(scene.glText) {
407396
for(i = 0; i < scene.textOptions.length; i++) {
408-
textOptions = scene.textOptions[i];
409-
for(j = 0; j < textOptions.length; j++) {
410-
scene.glText[i][j].update(textOptions[j]);
411-
}
397+
scene.glText[i].update(scene.textOptions[i]);
412398
}
413399
}
414400
if(scene.line2d) {
@@ -625,10 +611,8 @@ function plot(gd, subplot, cdata) {
625611
scene.select2d.update(vpRange);
626612
}
627613
if(scene.glText) {
628-
scene.glText.forEach(function(items, i) {
629-
items.forEach(function(item) {
630-
item.update(vpRange[i]);
631-
});
614+
scene.glText.forEach(function(text, i) {
615+
text.update(vpRange[i]);
632616
});
633617
}
634618

@@ -885,7 +869,7 @@ function selectPoints(searchInfo, polygon) {
885869
if(!selOptions) continue;
886870
textOptions = selOptions.textfont;
887871
if(!textOptions) continue;
888-
scene.glText[stash.index][el].update(textOptions[el]);
872+
// scene.glText[stash.index][el].update(textOptions[el]);
889873
}
890874
}
891875
if(unels) {
@@ -894,7 +878,7 @@ function selectPoints(searchInfo, polygon) {
894878
selOptions = scene.unselectedOptions[stash.index];
895879
if(!selOptions) continue;
896880
textOptions = selOptions.textfont || scene.textOptions[stash.index][el];
897-
scene.glText[stash.index][el].update(textOptions);
881+
// scene.glText[stash.index][el].update(textOptions);
898882
}
899883
}
900884
}

0 commit comments

Comments
 (0)