Skip to content
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

Build svg text #1783

Merged
merged 5 commits into from
Jun 13, 2017
Merged

Build svg text #1783

merged 5 commits into from
Jun 13, 2017

Conversation

alexcjohnson
Copy link
Collaborator

For our rich text displays: instead of converting pseudo-HTML into svg XML and then parsing this into elements, this PR converts the pseudo-HTML directly into <tspan> (and <a>) elements. Interestingly the speed gain isn't as pronounced as it was in #1776 using innerHTML but it helps a bit, and also addresses a couple of deficiencies in the previous version.

} else {
throw new Error('Cannot initialize DOMParser');
}
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🔪 DOMParser - but now replaced with something that's tested to work in IE 🎉


exports.xml_entity_encode = function(str) {
return str.replace(/&(?!\w+;|\#[0-9]+;| \#x[0-9A-F]+;)/g, '&amp;');
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

moved these encoders to snaphost/tosvg, which is now the only place they're used because svg_text_utils is creating text nodes directly, so doesn't need to do any conversion/sanitizing.

@@ -301,7 +301,8 @@ describe('svg+text utils', function() {
var node = mockTextSVGElement('SO<sub>4<br>44</sub>');
expect(node.html()).toBe(
'<tspan class="line" dy="0em">SO​' +
'<tspan style="font-size:70%" dy="0.3em">4</tspan></tspan>' +
'<tspan style="font-size:70%" dy="0.3em">4</tspan>' +
'<tspan dy="-0.21em">​</tspan></tspan>' +
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think this has any visual consequences, but <sup>/<sub> tags previously didn't get their proper reset elements when they spanned line breaks.

@@ -74,7 +74,7 @@ describe('svg+text utils', function() {
}

afterEach(function() {
d3.select('#text').remove();
d3.selectAll('.text-tester').remove();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the cases I added (previously and in the next commit) that test several input strings with identical output were not properly cleaned up with just select.

Copy link
Contributor

@etpinard etpinard Jun 13, 2017

Choose a reason for hiding this comment

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

Nice! I've seen those forgotten <text> nodes before while npm run test-jasmine. Thanks 🎉

var textCases = [
'<b><i><sup>many<br>lines<br>modified',
'<b><i><sup>many<br>lines<br>modified</sup></i></b>',
'<b><i><sup>many</sup><br><sup>lines</sup></i><br><i><sup>modified',
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This behavior is supported by regular HTML - and can be really useful to decouple styling from line breaks.

We tried weakly to support this previously but only allowed closing and reopening a single tag. The new version made it easy to handle arbitrary nesting.

@etpinard etpinard added status: reviewable bug something broken labels Jun 13, 2017
@etpinard etpinard added this to the 1.28.0 milestone Jun 13, 2017
@@ -264,19 +210,14 @@ var ENTITY_TO_UNICODE = Object.keys(stringMappings.entityToUnicode).map(function
};
});

var UNICODE_TO_ENTITY = Object.keys(stringMappings.unicodeToEntity).map(function(k) {
Copy link
Contributor

Choose a reason for hiding this comment

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

So, this part was useless?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see, right, this is useless now as we're building the text nodes directly instead of using window.DomParser. Nice!

currentNode = nodeStack[nodeStack.length - 1].node;
}

var hasLines = str.match(BR_TAG);
Copy link
Contributor

Choose a reason for hiding this comment

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

var hasLines = BR_TAG.test(str);

would be best here, as .test always returns a boolean. Moreover, I remember benchmarking regex.test vs str.match, and .test a while ago (RIP jsFiddle) came out on top.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nice catch! done in 3113795

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! 💃

@etpinard
Copy link
Contributor

Looks awesome. Building tspan nodes on our own should help us with text wrapping (one of plotly's long-standing issue: #382).

💃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants