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

Added support for multiline labels using explicit newline character. #4306

Merged
merged 34 commits into from
Dec 13, 2016

Conversation

dwhipps
Copy link
Contributor

@dwhipps dwhipps commented Sep 9, 2016

I've added support for multiline text in Labels using explicit newline characters, per this issue:

#2402

I revived and (very slightly) improved the code written by @Andre-Nunes in this pull request:

#2575

I've tested and ensured that single-line labels have the same positioning (i.e. this maintains backwards compatibility)

@hpinkos
Copy link
Contributor

hpinkos commented Sep 9, 2016

Thanks @dwhipps! It looks like you have a jsHint error
We'll take a look at this soon

@dwhipps
Copy link
Contributor Author

dwhipps commented Sep 9, 2016

Hannah,

I can't see the error on my end when running 'npm release' or 'npm tests-non-webgl'

Can you point me to the file/line? The "details" link in providing the Travis CI build log isn't very helpful.

// Subtract maxGlyphHeight for backwards compatibility
heightOffset += (totalHeight * scale) - maxGlyphHeight;
}
else if (verticalOrigin === VerticalOrigin.TOP) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@dwhipps this is causing the jsHint error, because this block is empty. You can just remove it.

You can run jsHint with npm run jsHint

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, update the formatting in the block above this while you're in there. It should be

} else if () {

@dwhipps
Copy link
Contributor Author

dwhipps commented Sep 13, 2016

I managed to fix the error. Not sure what the "bug bash" tag means. Do I have anything else to do?

@hpinkos
Copy link
Contributor

hpinkos commented Sep 13, 2016

Thanks @dwhipps, we're a little busy around here this week so I'm not sure if we'll have a chance to review this right away. I looked through and the code looks fine to me, but one of the graphics guys with a better understanding of the changes here will do a more thorough review to get this merged.

@mramato
Copy link
Contributor

mramato commented Sep 13, 2016

I know this code pretty well and this is a long overdue, mostly straightforward, change. I'll try and get it merged by the end of the week.

As for the bug bash label, we are having a 3-day code sprint in October to help address a lot of issues that have been reported in Cesium while most of us have been heads down on 3D Tiles related work. So the label just means that we definitely want to look at this for the sprint if it's not already merged by then.

@dwhipps
Copy link
Contributor Author

dwhipps commented Sep 15, 2016

I've discovered problems with this and have not yet been able to resolve them. It would recommend NOT pulling this until I've figured out what's going on.

@mramato
Copy link
Contributor

mramato commented Sep 15, 2016

Thanks for the heads up @dwhipps I had a few edge cases I wanted to be sure to check myself as well, so glad you're on the ball! Getting good font measurements in the browser is way harder than it should be (especially getting the same results cross-browser)

@dwhipps
Copy link
Contributor Author

dwhipps commented Sep 21, 2016

Red Herring. The new multiline labels code was not causing the issues I'm seeing (I'll report those separately.) As far as I can tell, it works pretty well.

@kring
Copy link
Member

kring commented Oct 8, 2016

@mramato I'm a little late to the party here, but I'm curious why measuring text has to be so hard. Can't we just ask the browser to do it? Here's how I did it recently in a similar situation:
https://github.com/TerriaJS/terriajs/blob/master/lib/Map/Legend.js#L188

In short: Create a span, set its styles and textContent, add it to the DOM (position: fixed so it doesn't affect layout, and opacity: 0 so it's not visible) and then call getBoundingClientRect.

One thing to keep in mind is that the measurement will be affected by the inherited CSS wherever you add the element, but you can deal with that pretty easily just by adding a class to your measure element that resets everything to a known state.

Worked well for my use-case (word wrapping in an SVG), anyway.

@hpinkos
Copy link
Contributor

hpinkos commented Oct 17, 2016

@dwhipps is this ready to be reviewed or were there still some things you wanted to change?

@dwhipps
Copy link
Contributor Author

dwhipps commented Oct 17, 2016

Yeah, this is ready to go.

@mramato
Copy link
Contributor

mramato commented Oct 17, 2016

In short: Create a span, set its styles and textContent, add it to the DOM (position: fixed so it doesn't affect layout, and opacity: 0 so it's not visible) and then call getBoundingClientRect.

It's been a while and I would need to look into it, but we also need to account for letter placement, i.e. letters that go below the baseline, like lowercase y. It's not just simple width/height we need to worry about.

@kring
Copy link
Member

kring commented Oct 19, 2016

we also need to account for letter placement, i.e. letters that go below the baseline, like lowercase y.

I don't think this should be an issue. The size of the span will account for any possible drop below the baseline. You can easily prove this to yourself with jsfiddle:
https://jsfiddle.net/srmvjdnn/1/

Change that o to a y or an R and notice that the height of the span doesn't change.

If you need to know the exact baseline position within that span for some reason, I don't know how to do that offhand, though I bet it can be done. But I can't really think of why you'd need to know that.

@mramato
Copy link
Contributor

mramato commented Oct 19, 2016

If you need to know the exact baseline position within that span for some reason, I don't know how to do that offhand, though I bet it can be done. But I can't really think of why you'd need to know that.

I think the main issue with your approach is the wasted space above the y. I'm less concerned about the memory/texture usage and more concerned with how that affects origin/offset positioning (though I admit it may not matter). @shunter was actually the original author for most of the current label code, so hopefully he can chime in with some thoughts. I'm fine with trying to approach you are suggesting, especially if it simplifies the code.

@mramato
Copy link
Contributor

mramato commented Oct 19, 2016

@dwhipps Check out the below code snippet and screenshot, I would expect the point to be dead center. It is in master (but without the new lines obviously). We need to make sure all of the various origin combinations work as expected.

var viewer = new Cesium.Viewer('cesiumContainer');
viewer.entities.add({
    position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
    point:{
        color: Cesium.Color.BLUE,
        pixelSize:15,
        verticalOrigin : Cesium.VerticalOrigin.CENTER,
        horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
    },
    label : {
        text : 'aa aa\naa aa\naa aa\naa aa',
        verticalOrigin : Cesium.VerticalOrigin.CENTER,
        horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
    }
});

image

@dwhipps
Copy link
Contributor Author

dwhipps commented Oct 19, 2016

Hmm. Well, now I've merge in master (just to keep things up to date) and the "Point" has disappeared. Can you confirm?

@dwhipps
Copy link
Contributor Author

dwhipps commented Oct 19, 2016

Looks like the "Point" is not drawing on the latest Chrome or Safari on Sierra, but it is working on FireFox...

@hpinkos
Copy link
Contributor

hpinkos commented Oct 19, 2016

I just checked out your branch @dwhipps and the point it still drawing for me in Chrome

@hpinkos
Copy link
Contributor

hpinkos commented Dec 7, 2016

@dwhipps you have a jsHint error:

Source/Scene/LabelCollection.js
line 270 col 51 'HeightReference' is not defined.
⚠ 1 warning

@emackey emackey mentioned this pull request Dec 7, 2016
6 tasks
@mramato
Copy link
Contributor

mramato commented Dec 8, 2016

Scene/LabelCollection Label should increase label height and decrease width when adding newlines is still failing in all browsers for me. Looking at the code, I think the problem is that Label.getScreenSpaceBoundingBox needs to be updated to actually support newline characters. Does this test pass for you @dwhipps?

@emackey
Copy link
Contributor

emackey commented Dec 8, 2016

@mramato @dwhipps The Label.getScreenSpaceBoundingBox function has a number of issues that are fixed on the label-backgrounds branch currently under review. I changed the logic for that function and more generally I revamped the logic for placing glyphs, so there will be major merge conflicts if someone attempts a simple merge of the two branches.

I want to take a shot at creating a multiline-label-backgrounds branch, hopefully today or tomorrow, that uses my new glyph placement logic augmented with the newline processing found here, and including backgrounds for multiline labels.

@dwhipps
Copy link
Contributor Author

dwhipps commented Dec 8, 2016

@emackey Good Luck! Let me know if you need anything. I'm around most of the day tomorrow.

@mramato
Copy link
Contributor

mramato commented Dec 8, 2016

Thanks @emackey, sounds like you have it under control!

@emackey
Copy link
Contributor

emackey commented Dec 9, 2016

Nice, GitHub allowed me to push to your branch since this PR is open. @dwhipps take a look at what changed here, and also try setting showBackground on a label with newline chars.

One intentional change I made is that HorizontalOrigin now controls text justification as well as the position relative to the anchor point. I didn't think it made sense to have left-justified text on a label when the anchor was CENTER or RIGHT.

justifytext

@mramato I think this is ready. Code I added should be reviewed. Thanks.

@emackey
Copy link
Contributor

emackey commented Dec 12, 2016

Updated doc & a demo. This is ready.

@mramato
Copy link
Contributor

mramato commented Dec 13, 2016

Sorry this took so long to get merged, but looks like the next Cesium release is going to have lots of nice label improvements. Thanks @dwhipps! and Thank @emackey for handling the merge and bounding box fixes.

@mramato mramato merged commit 9671dd9 into CesiumGS:master Dec 13, 2016
var maxY = 0;
var lastLineWidth = 0;
var maxLineWidth = 0;
var lineWidths = [];
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a scratch?

Copy link
Contributor

Choose a reason for hiding this comment

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

My hope is we don't need a scratch in this case. This function only gets called when the glyphs all need to be repositioned, which is an expensive operation we try to avoid (using the delay tactics you pointed out in the label background PR).

Copy link
Contributor

Choose a reason for hiding this comment

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

OK

if (glyphIndex < glyphLength - 1) {
var nextGlyph = glyphs[glyphIndex + 1];
glyphPixelOffset.x += ((dimensions.width - dimensions.bounds.minx) + nextGlyph.dimensions.bounds.minx) * scale * resolutionScale;
if (defined(backgroundBillboard) && (text.split('\n').join('').length > 0)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a more memory efficient way to do this?

text.split('\n').join('').length > 0

If so, does it matter here?

Copy link
Contributor

Choose a reason for hiding this comment

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

This too is part of repositionAllGlyphs and typically happens only when there is some substantial change made to the label.

@pjcozzi
Copy link
Contributor

pjcozzi commented Dec 13, 2016

Tests and Sandcastle look good. Is coverage for the new code solid? Just those trivial questions.

I'd like to get this into master soon for some use before the 1.29 release. Does anyone else want to look at this?

@pjcozzi
Copy link
Contributor

pjcozzi commented Dec 13, 2016

Ah, I see this was already merged; I had the window open from earlier today. 👍

@arafat5549
Copy link

does it able to have richtext?
like redblue !so i can display multi color text in one line !

@hpinkos
Copy link
Contributor

hpinkos commented Nov 8, 2017

Hi @arafat5549,
No, you can only have one text color for each label. In the future, please ask questions like this on our forum: https://groups.google.com/forum/?hl=en#!forum/cesium-dev
The forum has higher traffic so it is more likely someone will see your question and be able to help. We may miss your question if you comment on a closed pull request like this. Thanks!

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

Successfully merging this pull request may close these issues.

8 participants