I have a situation where I'm using Cesium.js entities to draw bearing lines from a point. In addition, I'd like to have a label attached to these bearing lines on the entity to show what it is. This is easy enough to do by attaching a label to the polyline entity. So far what I'm doing is creating a "really long" line along the bearing from the reference point and using the midpoint along that line as an anchor for the label (in Typescript):
let newEntity : Cesium.Entity;
let gccalc : gc.GreatCircle = new gc.GreatCircle();
let bearing : number = 45.0; //Bearing for the line
//this.currentPos is the lat/lon for the reference point for our bearing line
//gccalc is a simple class for computing great circle lines and has been omitted here (it is not relevant to the problem)
let destination = gccalc.destination(this.currentPos[0], this.currentPos[1], bearing, 1500, 'MI');
let anchorLabel = gccalc.destination(this.currentPos[0], this.currentPos[1], bearing, 50, 'MI');
const lineMat = new Cesium.PolylineDashMaterialProperty({
color : this.typeColorMap.get(contact.type)
});
const poses = Cesium.Cartesian3.fromDegreesArrayHeights([this.currentPos[1], this.currentPos[0], 500,
destination[1], destination[0], 500]); //500 is an arbitrary altitude for aesthetics
const nameString : string = "StringLabel";
let lineLabel = {
text: nameString,
font: '16px Helvetica',
fillColor : this.typeColorMap.get(contact.type),
outlineColor : Cesium.Color.BLACK,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.MIDDLE,
horizontalOrigin : Cesium.HorizontalOrigin.MIDDLE,
pixelOffset : new Cesium.Cartesian2(20, 0),
//pixelOffsetScaleByDistance : new Cesium.NearFarScalar(1.5e-1, 30.0, 1.5e7, 0.5)
};
let bearingLine = new Cesium.PolylineGraphics();
bearingLine.positions = poses;
bearingLine.width = 4;
bearingLine.material = lineMat;
bearingLine.arcType = Cesium.ArcType.NONE;
const lineEntity = {
name : 'Bearing Line',
polyline : bearingLine,
position : Cesium.Cartesian3.fromDegrees(anchorLabel[1], anchorLabel[0]),
show : true,
label : new Cesium.LabelGraphics(
lineLabel,
) as Cesium.LabelGraphics,
};
newEntity = new Cesium.Entity(lineEntity);
But the problem is the label is in geodesic (lat/lon) coordinates and does not stay on the screen as the user zooms in and out on the bearing line. So I also attempted to scale the position using the pixelOffsetScaleByDistance property, but this also doesn't work very well, and doesn't keep the label near the line under 3d rotations (because the X and Y scaling would technically have to change).
It seems what I really need are the screen-space positions of the line endpoints, and a way to create the entity label at that midpoint. Is there a way to do this? If not, what is the best way to ensure that my label is always near my polyline regardless of user interactions with the Cesium map (such as zooms and rotations)?
To give an idea of what I'm trying to do, here's a screencap of Cesium with the labels as implemented. They look correct here, but only because I've made sure the zoom level and rotation is correct: