Skip to content

Enable text for scattergl trace #2737

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 50 commits into from
Jul 5, 2018
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8ec98b9
Enable text-related attributes
dy Jun 14, 2018
862905c
Basic font rendering
dy Jun 15, 2018
d1a06c0
Make correct render output
dy Jun 15, 2018
cbc7f3f
Fix alignment
dy Jun 15, 2018
cc2cca1
use github 'regl-text'
etpinard Jun 18, 2018
e5a771c
Avoid double update
dy Jun 18, 2018
349b551
Fix image width
dy Jun 18, 2018
71c1acb
Add proper vertical alignment
dy Jun 20, 2018
4fe4e3a
Add textgl mocks
dy Jun 20, 2018
ff1d4fc
Use published gl-text package
dy Jun 20, 2018
95a3d1a
Compare license ignoring trailing spaces
dy Jun 20, 2018
ed7e0a0
Update deps
dy Jun 20, 2018
fa96cc7
Fix es5 word
dy Jun 20, 2018
9653fcf
Bump gl-util
dy Jun 21, 2018
17c1b0b
Add mocks
dy Jun 21, 2018
0154571
Fix mocks
dy Jun 21, 2018
c47d258
Unroll redundant change
dy Jun 21, 2018
79eae53
Bump gl-text deps
dy Jun 21, 2018
bd4491c
is isNumeric instead of typeof === 'number'
etpinard Jun 21, 2018
741bfb1
Rename mocks
dy Jun 21, 2018
4d67fa4
Fix panning
dy Jun 21, 2018
90479a7
Make text selection work
dy Jun 21, 2018
6def5e4
Fix text tests
dy Jun 21, 2018
47cf7e2
Make fast batch rendering
dy Jun 27, 2018
a53baf6
Make selection work
dy Jun 27, 2018
b3fb445
Bump gl-text
dy Jun 27, 2018
e09a4e1
Tmp fix
dy Jun 27, 2018
668d7ee
Fix undefined offsets/baseline
dy Jun 27, 2018
a41ea35
Bump gl-text
dy Jun 27, 2018
1702b30
Make selection work better
dy Jun 27, 2018
62bf263
Add baselines
dy Jun 27, 2018
65f97f3
Fix dep
dy Jun 27, 2018
55906cc
fixup package-lock
etpinard Jun 28, 2018
46bc623
clean up export names for scattergl/convert.js
etpinard Jun 28, 2018
7d75169
rename [un]selectedOptions -> marker{Unselected|Selected}Options
etpinard Jun 28, 2018
1a64005
cleanup scattergl text convert / select logic
etpinard Jun 28, 2018
bdc8f4a
apply [un]selected.textfont.color on plot
etpinard Jun 29, 2018
959a555
add & :lock: `hovertext` support for scattergl
etpinard Jun 29, 2018
431c564
fix & :lock: scattergl text visible toggles
etpinard Jun 29, 2018
9f3827c
add gl text chart select test
etpinard Jun 29, 2018
3af4d2f
use glText[0].regl to clear viewport during selection when `mode: 'te…
etpinard Jun 29, 2018
a83077b
Merge pull request #2770 from plotly/textgl-etienne
etpinard Jul 3, 2018
29fa2ef
Bump gl-text, fix safari
dy Jul 3, 2018
e462eda
fixup package-lock
etpinard Jul 4, 2018
52614d1
fix and :lock: selections + array textfont.color
etpinard Jul 4, 2018
143a61e
fixup selected textfont.color logic + add a few more tests
etpinard Jul 4, 2018
fb08f55
Bump gl-text
dy Jul 4, 2018
a5637dd
Update baselines
dy Jul 4, 2018
6aedaa6
Round texture shape
dy Jul 4, 2018
235f1ac
fixup package-lock
etpinard Jul 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,478 changes: 2,305 additions & 2,173 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"gl-select-box": "^1.0.2",
"gl-spikes2d": "^1.0.1",
"gl-surface3d": "^1.3.5",
"gl-text": "^1.0.1",
"glslify": "^6.1.1",
"has-hover": "^1.0.1",
"has-passive-events": "^1.0.0",
Expand Down
7 changes: 4 additions & 3 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,9 @@ drawing.tryColorscale = function(marker, prefix) {
else return Lib.identity;
};

var TEXTOFFSETSIGN = {start: 1, end: -1, middle: 0, bottom: 1, top: -1};
var TEXTOFFSETSIGN = {
start: 1, end: -1, middle: 0, bottom: 1, top: -1
};

function textPointPosition(s, textPosition, fontSize, markerRadius) {
var group = d3.select(s.node().parentNode);
Expand All @@ -622,8 +624,7 @@ function textPointPosition(s, textPosition, fontSize, markerRadius) {

var numLines = (svgTextUtils.lineCount(s) - 1) * LINE_SPACING + 1;
var dx = TEXTOFFSETSIGN[h] * r;
var dy = fontSize * 0.75 + TEXTOFFSETSIGN[v] * r +
(TEXTOFFSETSIGN[v] - 1) * numLines * fontSize / 2;
var dy = fontSize * 0.75 + TEXTOFFSETSIGN[v] * r + (TEXTOFFSETSIGN[v] - 1) * numLines * fontSize / 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you try not committing things like that in the future? Thank you.


// fix the overall text group position
s.attr('text-anchor', h);
Expand Down
12 changes: 9 additions & 3 deletions src/traces/scattergl/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ var attrs = module.exports = overrideAll({
'this trace\'s (x,y) coordinates.'
].join(' ')
}),

textposition: scatterAttrs.textposition,
textfont: scatterAttrs.textfont,

mode: {
valType: 'flaglist',
flags: ['lines', 'markers'],
flags: ['lines', 'markers', 'text'],
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that scattergl supports on-graph, we can add hovertext like in svg scatter traces:

hovertext: {
valType: 'string',
role: 'info',
dflt: '',
arrayOk: true,
editType: 'style',
description: [
'Sets hover text elements associated with each (x,y) pair.',
'If a single string, the same string appears over',
'all the data points.',
'If an array of string, the items are mapped in order to the',
'this trace\'s (x,y) coordinates.',
'To be seen, trace `hoverinfo` must contain a *text* flag.'
].join(' ')

Copy link
Contributor

Choose a reason for hiding this comment

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

done in 959a555

extras: ['none'],
role: 'info',
description: [
Expand Down Expand Up @@ -77,10 +81,12 @@ var attrs = module.exports = overrideAll({
hoveron: scatterAttrs.hoveron,

selected: {
marker: scatterAttrs.selected.marker
marker: scatterAttrs.selected.marker,
textfont: scatterAttrs.selected.textfont
},
unselected: {
marker: scatterAttrs.unselected.marker
marker: scatterAttrs.unselected.marker,
textfont: scatterAttrs.unselected.textfont
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this work? And what about selected.textfont?

Copy link
Contributor

Choose a reason for hiding this comment

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

Confirmed. selected.textfont.color and unselected.textfont.color do not work.

Copy link
Contributor

Choose a reason for hiding this comment

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

mostly done in 1a64005

},

opacity: plotAttrs.opacity
Expand Down
72 changes: 72 additions & 0 deletions src/traces/scattergl/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
var constants = require('./constants');
var DESELECTDIM = require('../../constants/interactions').DESELECTDIM;

var TEXTOFFSETSIGN = {
start: 1, left: 1, end: -1, right: -1, middle: 0, center: 0, bottom: 1, top: -1
};

function convertStyle(gd, trace) {
var i;

var opts = {
text: undefined,
marker: undefined,
line: undefined,
fill: undefined,
Expand All @@ -40,6 +45,66 @@ function convertStyle(gd, trace) {

if(trace.visible !== true) return opts;

if(subTypes.hasText(trace)) {
opts.text = [];

for(i = 0; i < trace.text.length; i++) {
var textOptions = opts.text[i] = {};

var textfont = unarr(trace.textfont, i);
var fontSize = unarr(textfont.size, i);
if(typeof fontSize !== 'number') {
continue;
}

textOptions.color = unarr(textfont.color, i);

textOptions.font = {
family: unarr(textfont.family, i),
size: fontSize
};


var textpos = unarr(trace.textposition, i);
textpos = textpos.split(/\s+/);
switch(textpos[1]) {
case 'left':
textOptions.align = 'right';
break;
case 'right':
textOptions.align = 'left';
break;
default:
textOptions.align = textpos[1];
}

switch(textpos[0]) {
case 'top':
textOptions.baseline = 'bottom';
break;
case 'bottom':
textOptions.baseline = 'top';
break;
default:
textOptions.baseline = textpos[0];
}

// corresponds to textPointPosition from component.drawing
if(trace.marker) {
var hSign = TEXTOFFSETSIGN[textOptions.align];
var markerRadius = unarr(unarr(trace.marker, i).size, i) / 2;
var xPad = markerRadius ? markerRadius / 0.8 + 1 : 0;
var vSign = TEXTOFFSETSIGN[textOptions.baseline];
var yPad = - vSign * xPad - vSign * 0.5;
textOptions.offset = [hSign * xPad / fontSize, yPad / fontSize];
}

textOptions.position = [unarr(trace.x, i), unarr(trace.y, i)];

textOptions.text = unarr(trace.text, i);
}
}

if(subTypes.hasMarkers(trace)) {
opts.marker = convertMarkerStyle(trace);
opts.selected = convertMarkerSelection(trace, trace.selected);
Expand Down Expand Up @@ -88,6 +153,13 @@ function convertStyle(gd, trace) {
return opts;
}


// FIXME: find proper util method for this
function unarr(obj, i) {
if(Array.isArray(obj)) return obj[i];
return obj;
}

function convertMarkerStyle(trace) {
var count = trace._length;
var optsIn = trace.marker;
Expand Down
8 changes: 7 additions & 1 deletion src/traces/scattergl/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var handleXYDefaults = require('../scatter/xy_defaults');
var handleMarkerDefaults = require('../scatter/marker_defaults');
var handleLineDefaults = require('../scatter/line_defaults');
var handleFillColorDefaults = require('../scatter/fillcolor_defaults');
var handleTextDefaults = require('../scatter/text_defaults');

module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
Expand All @@ -32,9 +33,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
traceOut.visible = false;
return;
}
var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';

coerce('text');
coerce('mode', len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines');
coerce('mode', defaultMode);

if(subTypes.hasLines(traceOut)) {
coerce('connectgaps');
Expand All @@ -49,6 +51,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
dfltHoverOn.push('points');
}

if(subTypes.hasText(traceOut)) {
handleTextDefaults(traceIn, traceOut, layout, coerce);
}

coerce('fill');
if(traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
Expand Down
60 changes: 59 additions & 1 deletion src/traces/scattergl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var createLine = require('regl-line2d');
var createError = require('regl-error2d');
var cluster = require('point-cluster');
var arrayRange = require('array-range');
var Text = require('gl-text');

var Registry = require('../../registry');
var Lib = require('../../lib');
Expand Down Expand Up @@ -103,6 +104,7 @@ function calc(gd, trace) {
if(opts.marker && !scene.scatter2d) scene.scatter2d = true;
if(opts.line && !scene.line2d) scene.line2d = true;
if((opts.errorX || opts.errorY) && !scene.error2d) scene.error2d = true;
if(opts.text && !scene.glText) scene.glText = true;

// FIXME: organize it in a more appropriate manner, probably in sceneOptions
// put point-cluster instance for optimized regl calc
Expand All @@ -118,6 +120,7 @@ function calc(gd, trace) {
scene.markerOptions.push(opts.marker);
scene.selectedOptions.push(opts.selected);
scene.unselectedOptions.push(opts.unselected);
scene.textOptions.push(opts.text);
scene.count++;

// stash scene ref
Expand All @@ -132,6 +135,7 @@ function calc(gd, trace) {
return [{x: false, y: false, t: stash, trace: trace}];
}


// create scene options
function sceneOptions(gd, subplot, trace, positions, x, y) {
var opts = convertStyle(gd, trace);
Expand Down Expand Up @@ -161,6 +165,7 @@ function sceneOptions(gd, subplot, trace, positions, x, y) {
return opts;
}


Copy link
Contributor

Choose a reason for hiding this comment

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

Again here. Please don't commit lines like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, but in this case all functions are separated by 2 new lines and here by just one, so hope you don't mind a bit of perfectionism

// make sure scene exists on subplot, return it
function sceneUpdate(gd, subplot) {
var scene = subplot._scene;
Expand All @@ -178,7 +183,8 @@ function sceneUpdate(gd, subplot) {
selectedOptions: [],
unselectedOptions: [],
errorXOptions: [],
errorYOptions: []
errorYOptions: [],
textOptions: []
};

var initOpts = {
Expand All @@ -189,6 +195,7 @@ function sceneUpdate(gd, subplot) {
scatter2d: false,
error2d: false,
line2d: false,
glText: false,
select2d: null
};

Expand All @@ -213,6 +220,11 @@ function sceneUpdate(gd, subplot) {
if(scene.line2d) scene.line2d.update(opts);
if(scene.error2d) scene.error2d.update(opts.concat(opts));
if(scene.select2d) scene.select2d.update(opts);
if(scene.glText) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you 🔪 this out?

// scene.glText.forEach(function (text) {
// text.update(opts);
// })
}

scene.draw();
};
Expand Down Expand Up @@ -248,6 +260,14 @@ function sceneUpdate(gd, subplot) {
scene.scatter2d.draw(scene.unselectBatch);
}

if(scene.glText.length) {
scene.glText.forEach(function(items) {
items.forEach(function(item) {
item.render();
});
});
}

scene.dirty = false;
};

Expand Down Expand Up @@ -293,7 +313,13 @@ function sceneUpdate(gd, subplot) {
if(scene.error2d) scene.error2d.destroy();
if(scene.line2d) scene.line2d.destroy();
if(scene.select2d) scene.select2d.destroy();
if(scene.glText) {scene.glText.forEach(function(items) {
items.forEach(function(item) {
item.destroy();
});
});}

scene.textOptions = null;
scene.lineOptions = null;
scene.fillOptions = null;
scene.markerOptions = null;
Expand All @@ -318,9 +344,12 @@ function sceneUpdate(gd, subplot) {
return scene;
}


function plot(gd, subplot, cdata) {
if(!cdata.length) return;

var i, j, items, textOptions;

var fullLayout = gd._fullLayout;
var scene = cdata[0][0].t._scene;
var dragmode = fullLayout.dragmode;
Expand Down Expand Up @@ -357,8 +386,27 @@ function plot(gd, subplot, cdata) {
if(scene.fill2d === true) {
scene.fill2d = createLine(regl);
}
if(scene.glText === true) {
scene.glText = [];
for(i = 0; i < scene.textOptions.length; i++) {
textOptions = scene.textOptions[i];
items = [];
for(j = 0; j < textOptions.length; j++) {
items.push(new Text(regl));
}
scene.glText[i] = items;
}
}

// update main marker options
if(scene.glText) {
for(i = 0; i < scene.textOptions.length; i++) {
textOptions = scene.textOptions[i];
for(j = 0; j < textOptions.length; j++) {
scene.glText[i][j].update(textOptions[j]);
}
}
}
if(scene.line2d) {
scene.line2d.update(scene.lineOptions);
}
Expand Down Expand Up @@ -572,12 +620,20 @@ function plot(gd, subplot, cdata) {
if(scene.select2d) {
scene.select2d.update(vpRange);
}
if(scene.glText) {
scene.glText.forEach(function(items, i) {
items.forEach(function(item) {
item.update(vpRange[i]);
});
});
}

scene.draw();

return;
}


function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var stash = cd[0].t;
Expand Down Expand Up @@ -816,6 +872,7 @@ function selectPoints(searchInfo, polygon) {
return selection;
}


function style(gd, cds) {
if(!cds) return;

Expand All @@ -831,6 +888,7 @@ function style(gd, cds) {
scene.draw();
}


module.exports = {
moduleType: 'trace',
name: 'scattergl',
Expand Down
5 changes: 4 additions & 1 deletion tasks/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ function updateHeadersInSrcFiles() {
});

function isCorrect(header) {
return (header.value === licenseStr);
return (
header.value.replace(/\s+$/gm, '') ===
Copy link
Contributor

@etpinard etpinard Jun 21, 2018

Choose a reason for hiding this comment

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

Is this for windows compat?

If so, I would prefer a different solution. Trimming spaces here could lead to false positive assertions.

Copy link
Contributor

Choose a reason for hiding this comment

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

never mind. Thanks for the fix!

licenseStr.replace(/\s+$/gm, '')
);
}

function hasWrongDate(header) {
Expand Down
Binary file modified test/image/baselines/gl2d_point-selection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/gl_text_chart_arrays.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/gl_text_chart_basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/gl_text_chart_styling.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading