import { BoundingRectangle } from "../../Source/Cesium.js"; import { BoundingSphere } from "../../Source/Cesium.js"; import { Cartesian2 } from "../../Source/Cesium.js"; import { Cartesian3 } from "../../Source/Cesium.js"; import { Color } from "../../Source/Cesium.js"; import { DistanceDisplayCondition } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { NearFarScalar } from "../../Source/Cesium.js"; import { Rectangle } from "../../Source/Cesium.js"; import { BlendOption } from "../../Source/Cesium.js"; import { Globe } from "../../Source/Cesium.js"; import { HeightReference } from "../../Source/Cesium.js"; import { HorizontalOrigin } from "../../Source/Cesium.js"; import { Label } from "../../Source/Cesium.js"; import { LabelCollection } from "../../Source/Cesium.js"; import { LabelStyle } from "../../Source/Cesium.js"; import { VerticalOrigin } from "../../Source/Cesium.js"; import createGlobe from "../createGlobe.js"; import createScene from "../createScene.js"; describe( "Scene/LabelCollection", function () { // TODO: rendering tests for pixel offset, eye offset, horizontal origin, vertical origin, font, style, outlineColor, outlineWidth, and fillColor properties var scene; var camera; var labels; var labelsWithHeight; // This Unicode square block will more reliably cover the center pixel than an 'x' or a 'w' char. var solidBox = "\u25a0"; beforeAll(function () { scene = createScene(); camera = scene.camera; }); afterAll(function () { scene.destroyForSpecs(); }); beforeEach(function () { scene.morphTo3D(0); camera.position = new Cartesian3(10.0, 0.0, 0.0); camera.direction = Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()); camera.up = Cartesian3.clone(Cartesian3.UNIT_Z); labels = new LabelCollection(); scene.primitives.add(labels); }); afterEach(function () { // labels are destroyed by removeAll(). scene.primitives.removeAll(); }); it("has default values when adding a label", function () { var label = labels.add(); expect(label.show).toEqual(true); expect(label.position).toEqual(Cartesian3.ZERO); expect(label.text).toEqual(""); expect(label.font).toEqual("30px sans-serif"); expect(label.fillColor).toEqual(Color.WHITE); expect(label.outlineColor).toEqual(Color.BLACK); expect(label.outlineWidth).toEqual(1); expect(label.showBackground).toEqual(false); expect(label.backgroundColor).toEqual( new Color(0.165, 0.165, 0.165, 0.8) ); expect(label.backgroundPadding).toEqual(new Cartesian2(7, 5)); expect(label.style).toEqual(LabelStyle.FILL); expect(label.pixelOffset).toEqual(Cartesian2.ZERO); expect(label.eyeOffset).toEqual(Cartesian3.ZERO); expect(label.heightReference).toEqual(HeightReference.NONE); expect(label.horizontalOrigin).toEqual(HorizontalOrigin.LEFT); expect(label.verticalOrigin).toEqual(VerticalOrigin.BASELINE); expect(label.scale).toEqual(1.0); expect(label.id).toBeUndefined(); expect(label.translucencyByDistance).toBeUndefined(); expect(label.pixelOffsetScaleByDistance).toBeUndefined(); expect(label.scaleByDistance).toBeUndefined(); expect(label.distanceDisplayCondition).toBeUndefined(); expect(label.disableDepthTestDistance).toBeUndefined(); }); it("can add a label with specified values", function () { var show = false; var position = new Cartesian3(1.0, 2.0, 3.0); var text = "abc"; var font = '24px "Open Sans"'; var fillColor = { red: 2.0, green: 3.0, blue: 4.0, alpha: 1.0, }; var outlineColor = { red: 3.0, green: 4.0, blue: 2.0, alpha: 1.0, }; var outlineWidth = 2; var style = LabelStyle.FILL_AND_OUTLINE; var pixelOffset = new Cartesian2(4.0, 5.0); var eyeOffset = new Cartesian3(6.0, 7.0, 8.0); var horizontalOrigin = HorizontalOrigin.LEFT; var verticalOrigin = VerticalOrigin.BOTTOM; var scale = 2.0; var showBackground = true; var backgroundColor = Color.BLUE; var backgroundPadding = new Cartesian2(11, 12); var translucency = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var pixelOffsetScale = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var scaleByDistance = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var distanceDisplayCondition = new DistanceDisplayCondition(10.0, 100.0); var disableDepthTestDistance = 10.0; var label = labels.add({ show: show, position: position, text: text, font: font, fillColor: fillColor, outlineColor: outlineColor, outlineWidth: outlineWidth, style: style, showBackground: showBackground, backgroundColor: backgroundColor, backgroundPadding: backgroundPadding, pixelOffset: pixelOffset, eyeOffset: eyeOffset, horizontalOrigin: horizontalOrigin, verticalOrigin: verticalOrigin, scale: scale, id: "id", translucencyByDistance: translucency, pixelOffsetScaleByDistance: pixelOffsetScale, scaleByDistance: scaleByDistance, distanceDisplayCondition: distanceDisplayCondition, disableDepthTestDistance: disableDepthTestDistance, }); expect(label.show).toEqual(show); expect(label.position).toEqual(position); expect(label.text).toEqual(text); expect(label.font).toEqual(font); expect(label.fillColor).toEqual(fillColor); expect(label.outlineColor).toEqual(outlineColor); expect(label.outlineWidth).toEqual(outlineWidth); expect(label.style).toEqual(style); expect(label.showBackground).toEqual(showBackground); expect(label.backgroundColor).toEqual(backgroundColor); expect(label.backgroundPadding).toEqual(backgroundPadding); expect(label.pixelOffset).toEqual(pixelOffset); expect(label.eyeOffset).toEqual(eyeOffset); expect(label.horizontalOrigin).toEqual(horizontalOrigin); expect(label.verticalOrigin).toEqual(verticalOrigin); expect(label.scale).toEqual(scale); expect(label.id).toEqual("id"); expect(label.translucencyByDistance).toEqual(translucency); expect(label.pixelOffsetScaleByDistance).toEqual(pixelOffsetScale); expect(label.scaleByDistance).toEqual(scaleByDistance); expect(label.distanceDisplayCondition).toEqual(distanceDisplayCondition); expect(label.disableDepthTestDistance).toEqual(disableDepthTestDistance); }); it("can specify font using units other than pixels", function () { var label = labels.add({ font: '12pt "Open Sans"', text: "Hello there", }); scene.renderForSpecs(); var dimensions = label._glyphs[0].dimensions; expect(dimensions.height).toBeGreaterThan(0); }); it("has zero labels when constructed", function () { expect(labels.length).toEqual(0); }); it("can add a label", function () { var label = labels.add(); expect(labels.length).toEqual(1); expect(labels.get(0)).toBe(label); }); it("can remove the first label", function () { var one = labels.add(); var two = labels.add(); expect(labels.contains(one)).toEqual(true); expect(labels.contains(two)).toEqual(true); expect(labels.remove(one)).toEqual(true); expect(labels.contains(one)).toEqual(false); expect(labels.contains(two)).toEqual(true); }); it("can remove the last label", function () { var one = labels.add(); var two = labels.add(); expect(labels.contains(one)).toEqual(true); expect(labels.contains(two)).toEqual(true); expect(labels.remove(two)).toEqual(true); expect(labels.contains(one)).toEqual(true); expect(labels.contains(two)).toEqual(false); }); it("returns false when removing undefined", function () { labels.add(); expect(labels.length).toEqual(1); expect(labels.remove(undefined)).toEqual(false); expect(labels.length).toEqual(1); }); it("returns false when removing a previously removed label", function () { var label = labels.add(); expect(labels.length).toEqual(1); expect(labels.remove(label)).toEqual(true); expect(labels.remove(label)).toEqual(false); expect(labels.length).toEqual(0); }); it("is not destroyed", function () { expect(labels.isDestroyed()).toEqual(false); }); it("can add and remove multiple labels", function () { var one = labels.add(); var two = labels.add(); var three = labels.add(); expect(labels.remove(one)).toEqual(true); expect(labels.remove(two)).toEqual(true); expect(one.isDestroyed()).toEqual(true); expect(two.isDestroyed()).toEqual(true); expect(three.isDestroyed()).toEqual(false); expect(labels.contains(one)).toEqual(false); expect(labels.contains(two)).toEqual(false); expect(labels.contains(three)).toEqual(true); expect(labels.length).toEqual(1); expect(labels.get(0)).toBe(three); var four = labels.add(); expect(labels.length).toEqual(2); expect(labels.get(0)).toBe(three); expect(labels.get(1)).toBe(four); expect(labels.contains(three)).toEqual(true); expect(labels.contains(four)).toEqual(true); }); it("can remove all labels", function () { labels.add({ position: new Cartesian3(1.0, 2.0, 3.0), }); labels.add({ position: new Cartesian3(4.0, 5.0, 6.0), }); expect(labels.length).toEqual(2); labels.removeAll(); expect(labels.length).toEqual(0); }); it("can check if it contains a label", function () { var label = labels.add(); expect(labels.contains(label)).toEqual(true); }); it("returns false when checking if it contains a label it does not contain", function () { var label = labels.add(); labels.remove(label); expect(labels.contains(label)).toEqual(false); }); it("does not contain undefined", function () { expect(labels.contains(undefined)).toEqual(false); }); it("does not contain random other objects", function () { expect(labels.contains({})).toEqual(false); expect(labels.contains(new Cartesian2())).toEqual(false); }); it("does not render when constructed", function () { expect(scene).toRender([0, 0, 0, 255]); }); it("can render after modifying and removing a label", function () { var labelOne = labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); labels.add({ position: Cartesian3.ZERO, text: "o", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); labelOne.scale = 2.0; labels.remove(labelOne); expect(scene).toRender([0, 0, 0, 255]); }); it("can render a label", function () { labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("renders in multiple passes", function () { labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); camera.position = new Cartesian3(2.0, 0.0, 0.0); var frameState = scene.frameState; frameState.commandList.length = 0; labels.blendOption = BlendOption.OPAQUE_AND_TRANSLUCENT; labels.update(frameState); expect(frameState.commandList.length).toEqual(2); frameState.commandList.length = 0; labels.blendOption = BlendOption.OPAQUE; labels.update(frameState); expect(frameState.commandList.length).toEqual(1); frameState.commandList.length = 0; labels.blendOption = BlendOption.TRANSLUCENT; labels.update(frameState); expect(frameState.commandList.length).toEqual(1); }); it("can render after adding a label", function () { labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(200); expect(rgba[1]).toBeGreaterThan(200); expect(rgba[2]).toBeGreaterThan(200); }); labels.add({ position: new Cartesian3(1.0, 0.0, 0.0), // Closer to camera text: solidBox, fillColor: { red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0, }, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(200); expect(rgba[1]).toBeLessThan(10); expect(rgba[2]).toBeLessThan(10); }); }); it("can render after removing a label", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); labels.remove(label); expect(scene).toRender([0, 0, 0, 255]); }); it("can render after removing and adding a label", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); labels.remove(label); labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("can render after removing all labels", function () { labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); labels.removeAll(); expect(scene).toRender([0, 0, 0, 255]); }); it("can render after removing all labels and adding a label", function () { labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); labels.removeAll(); labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("can render a label background", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "_", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, showBackground: true, backgroundColor: Color.BLUE, }); expect(scene).toRender([0, 0, 255, 255]); labels.remove(label); expect(scene).toRender([0, 0, 0, 255]); }); it("does not render labels with show set to false", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); label.show = false; expect(scene).toRender([0, 0, 0, 255]); label.show = true; expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("does not render label background with show set to false", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "_", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, showBackground: true, backgroundColor: Color.BLUE, }); expect(scene).toRender([0, 0, 255, 255]); label.show = false; expect(scene).toRender([0, 0, 0, 255]); label.show = true; expect(scene).toRender([0, 0, 255, 255]); }); it("does not render labels that are behind the viewer", function () { var label = labels.add({ position: Cartesian3.ZERO, // in front of the camera text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); label.position = new Cartesian3(20.0, 0.0, 0.0); // Behind camera expect(scene).toRender([0, 0, 0, 255]); label.position = new Cartesian3(1.0, 0.0, 0.0); // Back in front of camera expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("does not render labels with a scale of zero", function () { var label = labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); label.scale = 0.0; expect(scene).toRender([0, 0, 0, 255]); label.scale = 2.0; scene.render(); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); }); it("renders label with translucencyByDistance", function () { labels.add({ position: Cartesian3.ZERO, text: "x", horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, translucencyByDistance: new NearFarScalar(2.0, 1.0, 4.0, 0.0), }); camera.position = new Cartesian3(2.0, 0.0, 0.0); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); camera.position = new Cartesian3(4.0, 0.0, 0.0); expect(scene).toRender([0, 0, 0, 255]); }); it("renders label with pixelOffsetScaleByDistance", function () { labels.add({ position: Cartesian3.ZERO, pixelOffset: new Cartesian2(1.0, 0.0), text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, pixelOffsetScaleByDistance: new NearFarScalar(2.0, 0.0, 4.0, 1000.0), }); camera.position = new Cartesian3(2.0, 0.0, 0.0); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(10); }); camera.position = new Cartesian3(4.0, 0.0, 0.0); expect(scene).toRender([0, 0, 0, 255]); }); it("renders label with scaleByDistance", function () { labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, scaleByDistance: new NearFarScalar(2.0, 1.0, 4.0, 0.0), }); camera.position = new Cartesian3(2.0, 0.0, 0.0); expect(scene).toRender([255, 255, 255, 255]); camera.position = new Cartesian3(4.0, 0.0, 0.0); expect(scene).toRender([0, 0, 0, 255]); }); it("renders label with distanceDisplayCondition", function () { labels.add({ position: Cartesian3.ZERO, text: solidBox, distanceDisplayCondition: new DistanceDisplayCondition(10.0, 100.0), horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); camera.position = new Cartesian3(200.0, 0.0, 0.0); expect(scene).toRender([0, 0, 0, 255]); camera.position = new Cartesian3(50.0, 0.0, 0.0); expect(scene).toRenderAndCall(function (rgba) { expect(rgba[0]).toBeGreaterThan(200); expect(rgba[1]).toBeGreaterThan(200); expect(rgba[2]).toBeGreaterThan(200); }); camera.position = new Cartesian3(5.0, 0.0, 0.0); expect(scene).toRender([0, 0, 0, 255]); }); it("does not render label if show is false", function () { labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, scaleByDistance: new NearFarScalar(2.0, 1.0, 4.0, 0.0), }); camera.position = new Cartesian3(2.0, 0.0, 0.0); expect(scene).toRender([255, 255, 255, 255]); labels.show = false; expect(scene).toRender([0, 0, 0, 255]); }); it("throws new label with invalid distanceDisplayCondition (near >= far)", function () { var dc = new DistanceDisplayCondition(100.0, 10.0); expect(function () { labels.add({ distanceDisplayCondition: dc, }); }).toThrowDeveloperError(); }); it("throws distanceDisplayCondition with near >= far", function () { var l = labels.add(); var dc = new DistanceDisplayCondition(100.0, 10.0); expect(function () { l.distanceDisplayCondition = dc; }).toThrowDeveloperError(); }); it("renders with disableDepthTestDistance", function () { var l = labels.add({ position: new Cartesian3(-1.0, 0.0, 0.0), text: solidBox, fillColor: Color.LIME, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); labels.add({ position: Cartesian3.ZERO, text: solidBox, fillColor: Color.BLUE, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).toRender([0, 0, 255, 255]); l.disableDepthTestDistance = Number.POSITIVE_INFINITY; expect(scene).toRender([0, 255, 0, 255]); }); it("throws with new label with disableDepthTestDistance less than 0.0", function () { expect(function () { labels.add({ disableDepthTestDistance: -1.0, }); }).toThrowDeveloperError(); }); it("throws with disableDepthTestDistance set less than 0.0", function () { var l = labels.add(); expect(function () { l.disableDepthTestDistance = -1.0; }).toThrowDeveloperError(); }); it("can pick a label", function () { var label = labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, id: "id", }); expect(scene).toPickAndCall(function (result) { expect(result.primitive).toEqual(label); expect(result.id).toEqual("id"); }); }); it("can change pick id", function () { var label = labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, id: "id", }); expect(scene).toPickAndCall(function (result) { expect(result.primitive).toEqual(label); expect(result.id).toEqual("id"); }); label.id = "id2"; expect(scene).toPickAndCall(function (result) { expect(result.primitive).toEqual(label); expect(result.id).toEqual("id2"); }); }); it("does not pick a label with show set to false", function () { labels.add({ show: false, position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); expect(scene).notToPick(); }); it("picks a label using translucencyByDistance", function () { var label = labels.add({ position: Cartesian3.ZERO, text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); var translucency = new NearFarScalar(1.0, 0.9, 3.0e9, 0.8); label.translucencyByDistance = translucency; expect(scene).toPickPrimitive(label); translucency.nearValue = 0.0; translucency.farValue = 0.0; label.translucencyByDistance = translucency; expect(scene).notToPick(); }); it("picks a label using pixelOffsetScaleByDistance", function () { var label = labels.add({ position: Cartesian3.ZERO, pixelOffset: new Cartesian2(0.0, 100.0), text: solidBox, horizontalOrigin: HorizontalOrigin.CENTER, verticalOrigin: VerticalOrigin.CENTER, }); var pixelOffsetScale = new NearFarScalar(1.0, 0.0, 3.0e9, 0.0); label.pixelOffsetScaleByDistance = pixelOffsetScale; expect(scene).toPickPrimitive(label); pixelOffsetScale.nearValue = 10.0; pixelOffsetScale.farValue = 10.0; label.pixelOffsetScaleByDistance = pixelOffsetScale; expect(scene).notToPick(); }); it("throws when calling get without an index", function () { expect(function () { labels.get(); }).toThrowDeveloperError(); }); it("should reuse canvases for letters, but only if other settings are the same", function () { labels.add({ text: "a", }); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(1); labels.add({ text: "a", }); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(1); labels.add({ text: "abcd", }); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(4); labels.add({ text: "abc", }); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(4); var label = labels.add({ text: "de", }); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(5); var originalFont = label.font; label.font = '30px "Open Sans"'; expect(label.font).not.toEqual(originalFont); // otherwise this test needs fixing. scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); // Changing the outline doesn't cause new glyphs to be generated. label.style = LabelStyle.OUTLINE; scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); // Changing fill color doesn't cause new glyphs to be generated. label.fillColor = new Color(1.0, 165.0 / 255.0, 0.0, 1.0); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); // Changing outline color doesn't cause new glyphs to be generated. label.outlineColor = new Color(1.0, 1.0, 1.0, 1.0); scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); // vertical origin only affects glyph positions, not glyphs themselves. label.verticalOrigin = VerticalOrigin.CENTER; scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); label.verticalOrigin = VerticalOrigin.TOP; scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(7); //even though we're resetting to the original font, other properties used to create the id have changed label.font = originalFont; scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(9); //Changing thickness doesn't requires new glyphs label.outlineWidth = 3; scene.renderForSpecs(); expect(Object.keys(labels._glyphTextureCache).length).toEqual(9); }); it("should reuse billboards that are not needed any more", function () { var label = labels.add({ text: "abc", }); scene.renderForSpecs(); expect(labels._billboardCollection.length).toEqual(3); expect(labels._spareBillboards.length).toEqual(0); label.text = "a"; scene.renderForSpecs(); expect(labels._billboardCollection.length).toEqual(3); expect(labels._spareBillboards.length).toEqual(2); label.text = "def"; scene.renderForSpecs(); expect(labels._billboardCollection.length).toEqual(3); expect(labels._spareBillboards.length).toEqual(0); }); it("should not reuse background billboards that are not needed any more", function () { var label = labels.add({ text: "abc", showBackground: true, }); scene.renderForSpecs(); expect(labels._backgroundBillboardCollection.length).toEqual(1); label.showBackground = false; scene.renderForSpecs(); expect(labels._backgroundBillboardCollection.length).toEqual(0); label.showBackground = true; scene.renderForSpecs(); expect(labels._backgroundBillboardCollection.length).toEqual(1); }); describe( "Label", function () { it("can set properties after being added", function () { var label = labels.add(); var show = false; var position = new Cartesian3(1.0, 2.0, 3.0); var text = "abc"; var font = '24px "Open Sans"'; var fillColor = { red: 2.0, green: 3.0, blue: 4.0, alpha: 1.0, }; var outlineColor = { red: 3.0, green: 4.0, blue: 2.0, alpha: 1.0, }; var outlineWidth = 2; var style = LabelStyle.FILL_AND_OUTLINE; var pixelOffset = new Cartesian2(4.0, 5.0); var eyeOffset = new Cartesian3(6.0, 7.0, 8.0); var horizontalOrigin = HorizontalOrigin.LEFT; var verticalOrigin = VerticalOrigin.BOTTOM; var scale = 2.0; var translucency = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var pixelOffsetScale = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var scaleByDistance = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); label.show = show; label.position = position; label.text = text; label.font = font; label.fillColor = fillColor; label.outlineColor = outlineColor; label.outlineWidth = outlineWidth; label.style = style; label.pixelOffset = pixelOffset; label.eyeOffset = eyeOffset; label.horizontalOrigin = horizontalOrigin; label.verticalOrigin = verticalOrigin; label.scale = scale; label.translucencyByDistance = translucency; label.pixelOffsetScaleByDistance = pixelOffsetScale; label.scaleByDistance = scaleByDistance; expect(label.show).toEqual(show); expect(label.position).toEqual(position); expect(label.text).toEqual(text); expect(label.font).toEqual(font); expect(label.fillColor).toEqual(fillColor); expect(label.outlineColor).toEqual(outlineColor); expect(label.outlineWidth).toEqual(outlineWidth); expect(label.style).toEqual(style); expect(label.pixelOffset).toEqual(pixelOffset); expect(label.eyeOffset).toEqual(eyeOffset); expect(label.horizontalOrigin).toEqual(horizontalOrigin); expect(label.verticalOrigin).toEqual(verticalOrigin); expect(label.scale).toEqual(scale); expect(label.translucencyByDistance).toEqual(translucency); expect(label.pixelOffsetScaleByDistance).toEqual(pixelOffsetScale); expect(label.scaleByDistance).toEqual(scaleByDistance); }); it("is destroyed after being removed", function () { var label = labels.add(); expect(label.isDestroyed()).toEqual(false); labels.remove(label); expect(label.isDestroyed()).toEqual(true); }); it("throws after being removed", function () { var label = labels.add(); labels.remove(label); expect(function () { label.equals(label); }).toThrowDeveloperError(); }); it("can compute screen space position", function () { labels.clampToPixel = false; var label = labels.add({ text: "abc", position: Cartesian3.ZERO, }); scene.renderForSpecs(); expect(label.computeScreenSpacePosition(scene)).toEqualEpsilon( new Cartesian2(0.5, 0.5), CesiumMath.EPSILON1 ); }); it("stores screen space position in a result", function () { labels.clampToPixel = false; var label = labels.add({ text: "abc", position: Cartesian3.ZERO, }); var result = new Cartesian2(); scene.renderForSpecs(); var actual = label.computeScreenSpacePosition(scene, result); expect(actual).toEqual(result); expect(result).toEqualEpsilon( new Cartesian2(0.5, 0.5), CesiumMath.EPSILON1 ); }); it("can compute screen space position with pixelOffset", function () { labels.clampToPixel = false; var label = labels.add({ text: "abc", position: Cartesian3.ZERO, pixelOffset: new Cartesian2(0.5, 0.5), }); scene.renderForSpecs(); expect(label.computeScreenSpacePosition(scene)).toEqualEpsilon( new Cartesian2(1.0, 1.0), CesiumMath.EPSILON1 ); }); it("can compute screen space position with eyeOffset", function () { labels.clampToPixel = false; var label = labels.add({ text: "abc", position: Cartesian3.ZERO, eyeOffset: new Cartesian3(1.0, 1.0, 0.0), }); scene.renderForSpecs(); expect(label.computeScreenSpacePosition(scene)).toEqualEpsilon( new Cartesian2(0.5, 0.5), CesiumMath.EPSILON1 ); }); it("computes screen space bounding box", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, }); scene.renderForSpecs(); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.x).toBeDefined(); expect(bbox.y).toBeDefined(); expect(bbox.width).toBeGreaterThan(30); expect(bbox.width).toBeLessThan(200); expect(bbox.height).toBeGreaterThan(10); expect(bbox.height).toBeLessThan(50); }); it("computes screen space bounding box with result", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, }); scene.renderForSpecs(); var result = new BoundingRectangle(); var bbox = Label.getScreenSpaceBoundingBox( label, Cartesian2.ZERO, result ); expect(bbox.x).toBeDefined(); expect(bbox.y).toBeDefined(); expect(bbox.width).toBeGreaterThan(30); expect(bbox.width).toBeLessThan(200); expect(bbox.height).toBeGreaterThan(10); expect(bbox.height).toBeLessThan(50); expect(bbox).toBe(result); }); it("computes screen space bounding box with vertical origin center", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, verticalOrigin: VerticalOrigin.CENTER, }); scene.renderForSpecs(); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.y).toBeGreaterThan(bbox.height * -0.9); expect(bbox.y).toBeLessThan(bbox.height * -0.3); }); it("computes screen space bounding box with vertical origin top", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, verticalOrigin: VerticalOrigin.TOP, }); scene.renderForSpecs(); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.y).toBeLessThan(5); expect(bbox.y).toBeGreaterThan(-5); }); it("computes screen space bounding box with vertical origin baseline", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, verticalOrigin: VerticalOrigin.BASELINE, }); scene.renderForSpecs(); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.y).toBeLessThan(bbox.height * -0.8); expect(bbox.y).toBeGreaterThan(bbox.height * -1.2); }); it("computes screen space bounding box with horizontal origin", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, horizontalOrigin: HorizontalOrigin.CENTER, }); scene.renderForSpecs(); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.x).toBeLessThan(bbox.width * -0.3); expect(bbox.x).toBeGreaterThan(bbox.width * -0.7); label.horizontalOrigin = HorizontalOrigin.RIGHT; scene.renderForSpecs(); bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.x).toBeLessThan(bbox.width * -0.8); expect(bbox.x).toBeGreaterThan(bbox.width * -1.2); }); it("computes screen space bounding box with padded background", function () { var scale = 1.5; var label = labels.add({ text: "abc", scale: scale, showBackground: true, backgroundPadding: new Cartesian2(15, 10), }); scene.renderForSpecs(); var totalScale = label.scale * label._relativeSize; var backgroundBillboard = label._backgroundBillboard; var width = backgroundBillboard.width * totalScale; var height = backgroundBillboard.height * totalScale; var x = backgroundBillboard._translate.x; var y = -(backgroundBillboard._translate.y + height); var bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.x).toEqual(x); expect(bbox.y).toEqual(y); expect(bbox.width).toEqual(width); expect(bbox.height).toEqual(height); label.verticalOrigin = VerticalOrigin.CENTER; scene.renderForSpecs(); y = -(backgroundBillboard._translate.y + height * 0.5); bbox = Label.getScreenSpaceBoundingBox(label, Cartesian2.ZERO); expect(bbox.x).toEqual(x); expect(bbox.y).toEqual(y); expect(bbox.width).toEqual(width); expect(bbox.height).toEqual(height); }); it("can equal another label", function () { var label = labels.add({ position: new Cartesian3(1.0, 2.0, 3.0), text: "equals", }); var otherLabel = labels.add({ position: new Cartesian3(1.0, 2.0, 3.0), text: "equals", }); // This tests the `LabelCollection.equals` function itself, not simple equality. expect(label.equals(otherLabel)).toEqual(true); }); it("can differ from another label", function () { var label = labels.add({ position: new Cartesian3(1.0, 2.0, 3.0), }); var otherLabel = labels.add({ position: new Cartesian3(4.0, 5.0, 6.0), }); // This tests the `LabelCollection.equals` function itself, not simple equality. expect(label.equals(otherLabel)).toEqual(false); }); it("does not equal undefined", function () { // This tests the `LabelCollection.equals` function itself, not simple equality. var label = labels.add(); expect(label.equals(undefined)).toEqual(false); }); it("should have a number of glyphs equal to the number of characters", function () { var label = labels.add({ text: "abc", }); scene.renderForSpecs(); expect(label._glyphs.length).toEqual(3); label.text = "abcd"; scene.renderForSpecs(); expect(label._glyphs.length).toEqual(4); label.text = ""; scene.renderForSpecs(); expect(label._glyphs.length).toEqual(0); label = labels.add(); scene.renderForSpecs(); expect(label._glyphs.length).toEqual(0); }); it("does not create billboards for spaces", function () { var label = labels.add({ text: "abc", }); scene.renderForSpecs(); expect(label._glyphs.length).toEqual(3); expect(labels._billboardCollection.length).toEqual(3); label.text = " ab c"; scene.renderForSpecs(); expect(label._glyphs.length).toEqual(5); expect(labels._billboardCollection.length).toEqual(3); }); function getGlyphBillboardVertexTranslate(label, index) { return Cartesian2.clone( label._glyphs[index].billboard._translate, new Cartesian2() ); } function getBackgroundBillboardVertexTranslate(label) { return Cartesian2.clone( label._backgroundBillboard._translate, new Cartesian2() ); } it("sets billboard properties properly when they change on the label", function () { var position1 = new Cartesian3(1.0, 2.0, 3.0); var position2 = new Cartesian3(4.0, 5.0, 6.0); var pixelOffset1 = new Cartesian2(4.0, 5.0); var pixelOffset2 = new Cartesian2(6.0, 7.0); var eyeOffset1 = new Cartesian3(6.0, 7.0, 8.0); var eyeOffset2 = new Cartesian3(16.0, 17.0, 18.0); var verticalOrigin1 = VerticalOrigin.TOP; var verticalOrigin2 = VerticalOrigin.BASELINE; var scale1 = 2.0; var scale2 = 3.0; var id1 = "id1"; var id2 = "id2"; var translucency1 = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var translucency2 = new NearFarScalar(1.1e4, 1.2, 1.3e6, 4.0); var pixelOffsetScale1 = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var pixelOffsetScale2 = new NearFarScalar(1.5e4, 1.6, 1.7e6, 8.0); var scaleByDistance1 = new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0); var scaleByDistance2 = new NearFarScalar(1.5e4, 1.6, 1.7e6, 8.0); var label = labels.add({ position: position1, text: "abc", pixelOffset: pixelOffset1, eyeOffset: eyeOffset1, verticalOrigin: verticalOrigin1, scale: scale1, id: id1, translucencyByDistance: translucency1, pixelOffsetScaleByDistance: pixelOffsetScale1, scaleByDistance: scaleByDistance1, showBackground: true, }); scene.renderForSpecs(); label.position = position2; label.text = "def"; label.pixelOffset = pixelOffset2; label.eyeOffset = eyeOffset2; label.verticalOrigin = verticalOrigin2; label.scale = scale2; label.id = id2; label.translucencyByDistance = translucency2; label.pixelOffsetScaleByDistance = pixelOffsetScale2; label.scaleByDistance = scaleByDistance2; scene.renderForSpecs(); for (var i = 0; i < label._glyphs.length; ++i) { var glyph = label._glyphs[i]; var billboard = glyph.billboard; expect(billboard.show).toEqual(label.show); expect(billboard.position).toEqual(label.position); expect(billboard.eyeOffset).toEqual(label.eyeOffset); expect(billboard.pixelOffset).toEqual(label.pixelOffset); expect(billboard.verticalOrigin).toEqual(label.verticalOrigin); // glyph horizontal origin is always LEFT expect(billboard.scale).toEqual(label.scale * label._relativeSize); expect(billboard.id).toEqual(label.id); expect(billboard.translucencyByDistance).toEqual( label.translucencyByDistance ); expect(billboard.pixelOffsetScaleByDistance).toEqual( label.pixelOffsetScaleByDistance ); expect(billboard.scaleByDistance).toEqual(label.scaleByDistance); expect(billboard.pickPrimitive).toEqual(label); } }); describe("sets individual billboard properties properly when they change on the label", function () { var label; beforeEach(function () { label = labels.add({ position: new Cartesian3(1.0, 2.0, 3.0), text: "abc", pixelOffset: new Cartesian2(4.0, 5.0), eyeOffset: new Cartesian3(6.0, 7.0, 8.0), verticalOrigin: VerticalOrigin.TOP, scale: 2.0, id: "id1", translucencyByDistance: new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0), pixelOffsetScaleByDistance: new NearFarScalar( 1.0e4, 1.0, 1.0e6, 0.0 ), scaleByDistance: new NearFarScalar(1.0e4, 1.0, 1.0e6, 0.0), showBackground: true, }); scene.renderForSpecs(); }); function getGlyphBillboards() { return label._glyphs.map(function (glyph) { return glyph.billboard; }); } it("position", function () { var newValue = new Cartesian3(4.0, 5.0, 6.0); expect(label.position).not.toEqual(newValue); label.position = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.position).toEqual(label.position); }); }); it("eyeOffset", function () { var newValue = new Cartesian3(16.0, 17.0, 18.0); expect(label.eyeOffset).not.toEqual(newValue); label.eyeOffset = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.eyeOffset).toEqual(label.eyeOffset); }); }); it("pixelOffset", function () { var newValue = new Cartesian3(16.0, 17.0, 18.0); expect(label.pixelOffset).not.toEqual(newValue); label.pixelOffset = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.pixelOffset).toEqual(label.pixelOffset); }); }); it("verticalOrigin", function () { var newValue = VerticalOrigin.BOTTOM; expect(label.verticalOrigin).not.toEqual(newValue); label.verticalOrigin = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.verticalOrigin).toEqual(label.verticalOrigin); }); }); // glyph horizontal origin is always LEFT it("scale", function () { var newValue = 3.0; expect(label.scale).not.toEqual(newValue); label.scale = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.scale).toEqual(label.totalScale); }); }); it("showBackground", function () { expect(label.showBackground).toEqual(true); label.showBackground = false; expect(label.showBackground).toEqual(false); }); it("backgroundColor", function () { var newValue = Color.RED; expect(label.backgroundColor).not.toEqual(newValue); label.backgroundColor = newValue; expect(label.backgroundColor).toEqual(newValue); }); it("backgroundPadding", function () { var newValue = new Cartesian2(8, 5); expect(label.backgroundPadding).not.toEqual(newValue); label.backgroundPadding = newValue; expect(label.backgroundPadding).toEqual(newValue); }); it("id", function () { var newValue = "id2"; expect(label.id).not.toEqual(newValue); label.id = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.id).toEqual(label.id); }); }); it("translucencyByDistance", function () { var newValue = new NearFarScalar(1.1e4, 1.2, 1.3e6, 4.0); expect(label.translucencyByDistance).not.toEqual(newValue); label.translucencyByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.translucencyByDistance).toEqual( label.translucencyByDistance ); }); }); it("pixelOffsetScaleByDistance", function () { var newValue = new NearFarScalar(1.5e4, 1.6, 1.7e6, 8.0); expect(label.pixelOffsetScaleByDistance).not.toEqual(newValue); label.pixelOffsetScaleByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.pixelOffsetScaleByDistance).toEqual( label.pixelOffsetScaleByDistance ); }); }); it("scaleByDistance", function () { var newValue = new NearFarScalar(1.5e4, 1.6, 1.7e6, 8.0); expect(label.scaleByDistance).not.toEqual(newValue); label.scaleByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.scaleByDistance).toEqual(label.scaleByDistance); }); }); it("translucencyByDistance to undefined", function () { var newValue; expect(label.translucencyByDistance).not.toEqual(newValue); label.translucencyByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.translucencyByDistance).toEqual( label.translucencyByDistance ); }); }); it("pixelOffsetScaleByDistance to undefined", function () { var newValue; expect(label.pixelOffsetScaleByDistance).not.toEqual(newValue); label.pixelOffsetScaleByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.pixelOffsetScaleByDistance).toEqual( label.pixelOffsetScaleByDistance ); }); }); it("scaleByDistance to undefined", function () { var newValue; expect(label.scaleByDistance).not.toEqual(newValue); label.scaleByDistance = newValue; scene.renderForSpecs(); getGlyphBillboards().forEach(function (billboard) { expect(billboard.scaleByDistance).toEqual(label.scaleByDistance); }); }); it("clusterShow", function () { expect(label.clusterShow).toEqual(true); label.clusterShow = false; expect(label.clusterShow).toEqual(false); }); }); it("should set vertexTranslate of billboards correctly when vertical origin is changed", function () { var label = labels.add({ text: "apl", font: '90px "Open Sans"', verticalOrigin: VerticalOrigin.CENTER, }); scene.renderForSpecs(); // store the offsets when vertically centered var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); label.verticalOrigin = VerticalOrigin.TOP; scene.renderForSpecs(); // Because changing the label's vertical origin also changes the vertical origin of each // individual glyph, it is not safe to assume anything about Y offsets being more or less. // X offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).x).toEqual( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toEqual( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toEqual( offset2.x ); label.verticalOrigin = VerticalOrigin.BOTTOM; scene.renderForSpecs(); // X offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).x).toEqual( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toEqual( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toEqual( offset2.x ); }); it("should set vertexTranslate of billboards correctly when horizontal origin is changed", function () { var label = labels.add({ text: "apl", font: '90px "Open Sans"', horizontalOrigin: HorizontalOrigin.CENTER, showBackground: true, }); scene.renderForSpecs(); // store the offsets when horizontally centered var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); var offsetBack = getBackgroundBillboardVertexTranslate(label); label.horizontalOrigin = HorizontalOrigin.LEFT; scene.renderForSpecs(); // horizontal origin LEFT should increase X offset compared to CENTER expect(getGlyphBillboardVertexTranslate(label, 0).x).toBeGreaterThan( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toBeGreaterThan( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toBeGreaterThan( offset2.x ); expect( getBackgroundBillboardVertexTranslate(label).x ).toBeGreaterThan(offsetBack.x); // Y offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).y).toEqual( offset0.y ); expect(getGlyphBillboardVertexTranslate(label, 1).y).toEqual( offset1.y ); expect(getGlyphBillboardVertexTranslate(label, 2).y).toEqual( offset2.y ); expect(getBackgroundBillboardVertexTranslate(label).y).toEqual( offsetBack.y ); label.horizontalOrigin = HorizontalOrigin.RIGHT; scene.renderForSpecs(); // horizontal origin RIGHT should decrease X offset compared to CENTER expect(getGlyphBillboardVertexTranslate(label, 0).x).toBeLessThan( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toBeLessThan( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toBeLessThan( offset2.x ); expect(getBackgroundBillboardVertexTranslate(label).x).toBeLessThan( offsetBack.x ); // Y offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).y).toEqual( offset0.y ); expect(getGlyphBillboardVertexTranslate(label, 1).y).toEqual( offset1.y ); expect(getGlyphBillboardVertexTranslate(label, 2).y).toEqual( offset2.y ); expect(getBackgroundBillboardVertexTranslate(label).y).toEqual( offsetBack.y ); }); it("should set vertexTranslate of billboards correctly when scale is changed", function () { var label = labels.add({ text: "apl", font: '90px "Open Sans"', verticalOrigin: VerticalOrigin.CENTER, horizontalOrigin: HorizontalOrigin.CENTER, }); scene.renderForSpecs(); // store the offsets when vertically centered at scale 1 var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); label.scale = 2; scene.renderForSpecs(); // scaling by 2 should double X and Y offset expect(getGlyphBillboardVertexTranslate(label, 0).x).toEqual( 2 * offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 0).y).toEqual( 2 * offset0.y ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toEqual( 2 * offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 1).y).toEqual( 2 * offset1.y ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toEqual( 2 * offset2.x ); expect(getGlyphBillboardVertexTranslate(label, 2).y).toEqual( 2 * offset2.y ); // store the offsets when vertically centered at scale 2 offset0 = getGlyphBillboardVertexTranslate(label, 0); offset1 = getGlyphBillboardVertexTranslate(label, 1); offset2 = getGlyphBillboardVertexTranslate(label, 2); // Because changing the label's vertical origin also changes the vertical origin of each // individual glyph, it is not safe to assume anything about Y offsets being more or less. label.horizontalOrigin = HorizontalOrigin.LEFT; scene.renderForSpecs(); // horizontal origin LEFT should increase X offset compared to CENTER expect(getGlyphBillboardVertexTranslate(label, 0).x).toBeGreaterThan( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toBeGreaterThan( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toBeGreaterThan( offset2.x ); // Y offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).y).toEqual( offset0.y ); expect(getGlyphBillboardVertexTranslate(label, 1).y).toEqual( offset1.y ); expect(getGlyphBillboardVertexTranslate(label, 2).y).toEqual( offset2.y ); label.horizontalOrigin = HorizontalOrigin.RIGHT; scene.renderForSpecs(); // horizontal origin RIGHT should decrease X offset compared to CENTER expect(getGlyphBillboardVertexTranslate(label, 0).x).toBeLessThan( offset0.x ); expect(getGlyphBillboardVertexTranslate(label, 1).x).toBeLessThan( offset1.x ); expect(getGlyphBillboardVertexTranslate(label, 2).x).toBeLessThan( offset2.x ); // Y offset should be unchanged expect(getGlyphBillboardVertexTranslate(label, 0).y).toEqual( offset0.y ); expect(getGlyphBillboardVertexTranslate(label, 1).y).toEqual( offset1.y ); expect(getGlyphBillboardVertexTranslate(label, 2).y).toEqual( offset2.y ); }); it("label vertex translate should remain the same when pixel offset is changed", function () { var label = labels.add({ text: "apl", font: '90px "Open Sans"', }); scene.renderForSpecs(); var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); var xOffset = 20; var yOffset = -10; label.pixelOffset = new Cartesian2(xOffset, yOffset); scene.renderForSpecs(); expect(getGlyphBillboardVertexTranslate(label, 0)).toEqual(offset0); expect(getGlyphBillboardVertexTranslate(label, 1)).toEqual(offset1); expect(getGlyphBillboardVertexTranslate(label, 2)).toEqual(offset2); expect(label.pixelOffset.x).toEqual(xOffset); expect(label.pixelOffset.y).toEqual(yOffset); }); it("Correctly updates billboard position when height reference changes", function () { scene.globe = new Globe(); var labelsWithScene = new LabelCollection({ scene: scene }); scene.primitives.add(labelsWithScene); var position1 = new Cartesian3(1.0, 2.0, 3.0); var label = labelsWithScene.add({ position: position1, text: "abc", heightReference: HeightReference.CLAMP_TO_GROUND, }); scene.renderForSpecs(); var glyph = label._glyphs[0]; var billboard = glyph.billboard; expect(billboard.position).toEqual(label.position); label.heightReference = HeightReference.NONE; scene.renderForSpecs(); expect(billboard.position).toEqual(label.position); scene.primitives.remove(labelsWithScene); }); it("should set vertexTranslate of billboards correctly when font size changes", function () { var label = labels.add({ text: "apl", font: '80px "Open Sans"', verticalOrigin: VerticalOrigin.TOP, horizontalOrigin: HorizontalOrigin.LEFT, }); scene.renderForSpecs(); var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); label.font = '20px "Open Sans"'; scene.renderForSpecs(); // reducing font size should reduce absolute value of both X and Y offset expect( Math.abs(getGlyphBillboardVertexTranslate(label, 0).x) ).toBeLessThanOrEqualTo(Math.abs(offset0.x)); expect( Math.abs(getGlyphBillboardVertexTranslate(label, 0).y) ).toBeLessThanOrEqualTo(Math.abs(offset0.y)); expect( Math.abs(getGlyphBillboardVertexTranslate(label, 1).x) ).toBeLessThanOrEqualTo(Math.abs(offset1.x)); expect( Math.abs(getGlyphBillboardVertexTranslate(label, 1).y) ).toBeLessThanOrEqualTo(Math.abs(offset1.y)); expect( Math.abs(getGlyphBillboardVertexTranslate(label, 2).x) ).toBeLessThanOrEqualTo(Math.abs(offset2.x)); expect( Math.abs(getGlyphBillboardVertexTranslate(label, 2).y) ).toBeLessThanOrEqualTo(Math.abs(offset2.y)); }); it("should have the same vertexTranslate of billboards whether values are set at construction or afterwards", function () { var text = "apl"; var scale = 2.0; var font = '20px "Open Sans"'; var verticalOrigin = VerticalOrigin.CENTER; var pixelOffset = new Cartesian2(10.0, 15.0); var one = labels.add({ text: text, scale: scale, font: font, verticalOrigin: verticalOrigin, pixelOffset: pixelOffset, }); scene.renderForSpecs(); var two = labels.add(); two.text = text; two.scale = scale; two.font = font; two.verticalOrigin = verticalOrigin; two.pixelOffset = pixelOffset; scene.renderForSpecs(); expect(getGlyphBillboardVertexTranslate(one, 0)).toEqual( getGlyphBillboardVertexTranslate(two, 0) ); expect(getGlyphBillboardVertexTranslate(one, 1)).toEqual( getGlyphBillboardVertexTranslate(two, 1) ); expect(getGlyphBillboardVertexTranslate(one, 2)).toEqual( getGlyphBillboardVertexTranslate(two, 2) ); }); it("should not change vertexTranslate of billboards when position changes", function () { var label = labels.add({ text: "apl", }); scene.renderForSpecs(); var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); label.position = new Cartesian3(1.0, 1.0, 1.0); scene.renderForSpecs(); expect(getGlyphBillboardVertexTranslate(label, 0)).toEqual(offset0); expect(getGlyphBillboardVertexTranslate(label, 1)).toEqual(offset1); expect(getGlyphBillboardVertexTranslate(label, 2)).toEqual(offset2); }); it("should not change vertexTranslate of billboards when eye offset changes", function () { var label = labels.add({ text: "apl", }); scene.renderForSpecs(); var offset0 = getGlyphBillboardVertexTranslate(label, 0); var offset1 = getGlyphBillboardVertexTranslate(label, 1); var offset2 = getGlyphBillboardVertexTranslate(label, 2); label.eyeOffset = new Cartesian3(10.0, 10.0, -10.0); scene.renderForSpecs(); expect(getGlyphBillboardVertexTranslate(label, 0)).toEqual(offset0); expect(getGlyphBillboardVertexTranslate(label, 1)).toEqual(offset1); expect(getGlyphBillboardVertexTranslate(label, 2)).toEqual(offset2); }); it("should not change label dimensions when scale changes", function () { var label = labels.add({ text: "apl", }); scene.renderForSpecs(); var originalDimensions = label._glyphs[0].dimensions; label.scale = 3; scene.renderForSpecs(); var dimensions = label._glyphs[0].dimensions; expect(dimensions.width).toEqual(originalDimensions.width); expect(dimensions.height).toEqual(originalDimensions.height); expect(dimensions.descent).toEqual(originalDimensions.descent); }); it("should not change label dimensions when font size changes", function () { var label = labels.add({ text: "apl", font: '90px "Open Sans"', }); scene.renderForSpecs(); var originalDimensions = label._glyphs[0].dimensions; label.font = '20px "Open Sans"'; scene.renderForSpecs(); var dimensions = label._glyphs[0].dimensions; expect(dimensions.width).toEqual(originalDimensions.width); expect(dimensions.height).toEqual(originalDimensions.height); expect(dimensions.descent).toEqual(originalDimensions.descent); }); it("should increase label height and decrease width when adding newlines", function () { var label = labels.add({ text: "apl apl apl", }); scene.renderForSpecs(); var originalBbox = Label.getScreenSpaceBoundingBox( label, Cartesian2.ZERO ); label.text = "apl\napl\napl"; scene.renderForSpecs(); var newlinesBbox = Label.getScreenSpaceBoundingBox( label, Cartesian2.ZERO ); expect(newlinesBbox.width).toBeLessThan(originalBbox.width); expect(newlinesBbox.height).toBeGreaterThan(originalBbox.height); }); it("should not modify text when rightToLeft is false", function () { var text = "bla bla bla"; var label = labels.add({ text: text, }); scene.renderForSpecs(); expect(label.text).toEqual(text); }); it("filters out soft hyphens from input strings", function () { var softHyphen = String.fromCharCode(0xad); var text = "test string" + softHyphen; var label = labels.add({ text: text, }); scene.renderForSpecs(); expect(label.text).toEqual(text); expect(label._renderedText).toEqual("test string"); }); }, "WebGL" ); describe("right to left detection", function () { beforeAll(function () { Label.enableRightToLeftDetection = true; }); afterAll(function () { Label.enableRightToLeftDetection = false; }); it("should not modify text when rightToLeft is true and there are no RTL characters", function () { var text = "bla bla bla"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); }); it("should reverse text when there are only hebrew characters and rightToLeft is true", function () { var text = "שלום"; var expectedText = "םולש"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should reverse text when there are only arabic characters and rightToLeft is true", function () { var text = "مرحبا"; var expectedText = "ابحرم"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should reverse part of text when there is mix of right-to-left and other kind of characters and rightToLeft is true", function () { var text = 'Master (אדון): "Hello"\nתלמיד (student): "שלום"'; var expectedText = 'Master (ןודא): "Hello"\n"םולש" :(student) דימלת'; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should reverse all text and replace brackets when there is right-to-left characters and rightToLeft is true", function () { var text = "משפט [מורכב] {עם} תווים <מיוחדים special>"; var expectedText = " םיוות {םע} [בכרומ] טפשמ"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should reverse only text that detected as rtl text when it begin with non rtl characters when rightToLeft is true", function () { var text = "(interesting sentence with hebrew characters) שלום(עליך)חביבי."; var expectedText = "(interesting sentence with hebrew characters) יביבח(ךילע)םולש."; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should not change nothing if it only non alphanumeric characters when rightToLeft is true", function () { var text = "([{- -}])"; var expectedText = "([{- -}])"; var label = labels.add({ text: text, }); expect(label.text).toEqual(expectedText); }); it("detects characters in the range \\u05D0-\\u05EA", function () { var text = "\u05D1\u05D2"; var expectedText = "\u05D2\u05D1"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("detects characters in the range \\u0600-\\u06FF", function () { var text = "\u0601\u0602"; var expectedText = "\u0602\u0601"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("detects characters in the range \\u0750-\\u077F", function () { var text = "\u0751\u0752"; var expectedText = "\u0752\u0751"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("detects characters in the range \\u08A0-\\u08FF", function () { var text = "\u08A1\u08A2"; var expectedText = "\u08A2\u08A1"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); it("should reversing correctly non alphabetic characters", function () { var text = "A אב: ג\nאב: ג"; var expectedText = "A ג :בא\nג :בא"; var label = labels.add({ text: text, }); expect(label.text).toEqual(text); expect(label._renderedText).toEqual(expectedText); }); }); it("computes bounding sphere in 3D", function () { var one = labels.add({ position: Cartesian3.fromDegrees(-50.0, -50.0, 0.0), text: "one", }); var two = labels.add({ position: Cartesian3.fromDegrees(-50.0, 50.0, 0.0), text: "two", }); scene.renderForSpecs(); var actual = scene.frameState.commandList[0].boundingVolume; var positions = [one.position, two.position]; var expected = BoundingSphere.fromPoints(positions); expect(actual.center).toEqual(expected.center); expect(actual.radius).toEqual(expected.radius); }); it("computes bounding sphere in Columbus view", function () { // Disable collision detection to allow controlled camera position, // hence predictable bounding sphere size var originalEnableCollisionDetection = scene.screenSpaceCameraController.enableCollisionDetection; scene.screenSpaceCameraController.enableCollisionDetection = false; var projection = scene.mapProjection; var ellipsoid = projection.ellipsoid; var one = labels.add({ position: Cartesian3.fromDegrees(-50.0, -50.0, 0.0), text: "one", }); var two = labels.add({ position: Cartesian3.fromDegrees(-50.0, 50.0, 0.0), text: "two", }); // Update scene state scene.morphToColumbusView(0); scene.renderForSpecs(); var actual = scene.frameState.commandList[0].boundingVolume; var projectedPositions = [ projection.project(ellipsoid.cartesianToCartographic(one.position)), projection.project(ellipsoid.cartesianToCartographic(two.position)), ]; var expected = BoundingSphere.fromPoints(projectedPositions); expected.center = new Cartesian3( 0.0, expected.center.x, expected.center.y ); expect(actual.center).toEqualEpsilon( expected.center, CesiumMath.EPSILON8 ); expect(actual.radius).toBeGreaterThanOrEqualTo(expected.radius); scene.screenSpaceCameraController.enableCollisionDetection = originalEnableCollisionDetection; }); it("computes bounding sphere in 2D", function () { var projection = scene.mapProjection; var ellipsoid = projection.ellipsoid; var one = labels.add({ position: Cartesian3.fromDegrees(-50.0, -50.0), text: "one", }); var two = labels.add({ position: Cartesian3.fromDegrees(-50.0, 50.0), text: "two", }); camera.setView({ destination: Rectangle.fromDegrees(-60.0, -60.0, -40.0, 60.0), }); scene.morphTo2D(0); scene.renderForSpecs(); scene.renderForSpecs(); var actual = scene.frameState.commandList[0].boundingVolume; var projectedPositions = [ projection.project(ellipsoid.cartesianToCartographic(one.position)), projection.project(ellipsoid.cartesianToCartographic(two.position)), ]; var expected = BoundingSphere.fromPoints(projectedPositions); expected.center = new Cartesian3( 0.0, expected.center.x, expected.center.y ); expect(actual.center).toEqualEpsilon( expected.center, CesiumMath.EPSILON8 ); expect(actual.radius).toBeGreaterThan(expected.radius); }); it("Label.show throws with undefined", function () { var label = labels.add(); expect(function () { label.show = undefined; }).toThrowDeveloperError(); }); it("Label.position throws with undefined", function () { var label = labels.add(); expect(function () { label.position = undefined; }).toThrowDeveloperError(); }); it("Label.text throws with undefined", function () { var label = labels.add(); expect(function () { label.text = undefined; }).toThrowDeveloperError(); }); it("Label.font throws with undefined", function () { var label = labels.add(); expect(function () { label.font = undefined; }).toThrowDeveloperError(); }); it("Label.fillColor throws with undefined", function () { var label = labels.add(); expect(function () { label.fillColor = undefined; }).toThrowDeveloperError(); }); it("Label.outlineColor throws with undefined", function () { var label = labels.add(); expect(function () { label.outlineColor = undefined; }).toThrowDeveloperError(); }); it("Label.outlineWidth throws with undefined", function () { var label = labels.add(); expect(function () { label.outlineWidth = undefined; }).toThrowDeveloperError(); }); it("Label.style throws with undefined", function () { var label = labels.add(); expect(function () { label.style = undefined; }).toThrowDeveloperError(); }); it("Label.pixelOffset throws with undefined", function () { var label = labels.add(); expect(function () { label.pixelOffset = undefined; }).toThrowDeveloperError(); }); it("Label.eyeOffset throws with undefined", function () { var label = labels.add(); expect(function () { label.eyeOffset = undefined; }).toThrowDeveloperError(); }); it("Label.horizontalOrigin throws with undefined", function () { var label = labels.add(); expect(function () { label.horizontalOrigin = undefined; }).toThrowDeveloperError(); }); it("Label.verticalOrigin throws with undefined", function () { var label = labels.add(); expect(function () { label.verticalOrigin = undefined; }).toThrowDeveloperError(); }); it("Label.scale throws with undefined", function () { var label = labels.add(); expect(function () { label.scale = undefined; }).toThrowDeveloperError(); }); it("Label.computeScreenSpacePosition throws with undefined scene", function () { var label = labels.add(); expect(function () { label.computeScreenSpacePosition(); }).toThrowDeveloperError(); }); it("Label.translucencyByDistance throws with nearDistance === farDistance", function () { var label = labels.add(); var translucency = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { label.translucencyByDistance = translucency; }).toThrowDeveloperError(); }); it("Label.pixelOffsetScaleByDistance throws with nearDistance === farDistance", function () { var label = labels.add(); var pixelOffsetScale = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { label.pixelOffsetScaleByDistance = pixelOffsetScale; }).toThrowDeveloperError(); }); it("Label.scaleByDistance throws with nearDistance === farDistance", function () { var label = labels.add(); var scaleByDistance = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { label.scaleByDistance = scaleByDistance; }).toThrowDeveloperError(); }); it("new label throws with invalid translucencyByDistance (nearDistance === farDistance)", function () { var translucency = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { labels.add({ translucencyByDistance: translucency, }); }).toThrowDeveloperError(); }); it("new label throws with invalid pixelOffsetScaleByDistance (nearDistance === farDistance)", function () { var pixelOffsetScale = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { labels.add({ pixelOffsetScaleByDistance: pixelOffsetScale, }); }).toThrowDeveloperError(); }); it("new label throws with invalid scaleByDistance (nearDistance === farDistance)", function () { var scaleByDistance = new NearFarScalar(2.0e5, 1.0, 2.0e5, 0.0); expect(function () { labels.add({ scaleByDistance: scaleByDistance, }); }).toThrowDeveloperError(); }); it("Label.translucencyByDistance throws with nearDistance > farDistance", function () { var label = labels.add(); var translucency = new NearFarScalar(1.0e9, 1.0, 1.0e5, 1.0); expect(function () { label.translucencyByDistance = translucency; }).toThrowDeveloperError(); }); it("Label.pixelOffsetScaleByDistance throws with nearDistance > farDistance", function () { var label = labels.add(); var pixelOffsetScale = new NearFarScalar(1.0e9, 1.0, 1.0e5, 1.0); expect(function () { label.pixelOffsetScaleByDistance = pixelOffsetScale; }).toThrowDeveloperError(); }); it("Label.scaleByDistance throws with nearDistance > farDistance", function () { var label = labels.add(); var scaleByDistance = new NearFarScalar(1.0e9, 1.0, 1.0e5, 1.0); expect(function () { label.scaleByDistance = scaleByDistance; }).toThrowDeveloperError(); }); it("destroys texture atlas when destroying", function () { labels.add({ text: "a", }); scene.renderForSpecs(); var textureAtlas = labels._textureAtlas; expect(textureAtlas.isDestroyed()).toBe(false); scene.primitives.removeAll(); expect(textureAtlas.isDestroyed()).toBe(true); }); describe("height referenced labels", function () { beforeEach(function () { scene.globe = createGlobe(); labelsWithHeight = new LabelCollection({ scene: scene, }); scene.primitives.add(labelsWithHeight); }); it("explicitly constructs a label with height reference", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ text: "test", heightReference: HeightReference.CLAMP_TO_GROUND, }); expect(l.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); }); it("set label height reference property", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ text: "test", }); l.heightReference = HeightReference.CLAMP_TO_GROUND; expect(l.heightReference).toEqual(HeightReference.CLAMP_TO_GROUND); }); it("creating with a height reference creates a height update callback", function () { scene.globe = createGlobe(); labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, position: Cartesian3.fromDegrees(-72.0, 40.0), }); expect(scene.globe.callback).toBeDefined(); }); it("set height reference property creates a height update callback", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ position: Cartesian3.fromDegrees(-72.0, 40.0), }); l.heightReference = HeightReference.CLAMP_TO_GROUND; expect(scene.globe.callback).toBeDefined(); }); it("updates the callback when the height reference changes", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, position: Cartesian3.fromDegrees(-72.0, 40.0), }); expect(scene.globe.callback).toBeDefined(); l.heightReference = HeightReference.RELATIVE_TO_GROUND; expect(scene.globe.removedCallback).toEqual(true); expect(scene.globe.callback).toBeDefined(); scene.globe.removedCallback = false; l.heightReference = HeightReference.NONE; expect(scene.globe.removedCallback).toEqual(true); expect(scene.globe.callback).toBeUndefined(); }); it("changing the position updates the callback", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, position: Cartesian3.fromDegrees(-72.0, 40.0), }); expect(scene.globe.callback).toBeDefined(); l.position = Cartesian3.fromDegrees(-73.0, 40.0); expect(scene.globe.removedCallback).toEqual(true); expect(scene.globe.callback).toBeDefined(); }); it("callback updates the position", function () { scene.globe = createGlobe(); var l = labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, position: Cartesian3.fromDegrees(-72.0, 40.0), }); expect(scene.globe.callback).toBeDefined(); var cartographic = scene.globe.ellipsoid.cartesianToCartographic( l._clampedPosition ); expect(cartographic.height).toEqual(0.0); scene.globe.callback(Cartesian3.fromDegrees(-72.0, 40.0, 100.0)); cartographic = scene.globe.ellipsoid.cartesianToCartographic( l._clampedPosition ); expect(cartographic.height).toEqualEpsilon(100.0, CesiumMath.EPSILON9); }); it("resets the clamped position when HeightReference.NONE", function () { scene.globe = createGlobe(); spyOn(scene.camera, "update"); var l = labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, text: "t", position: Cartesian3.fromDegrees(-72.0, 40.0), }); scene.renderForSpecs(); expect(l._clampedPosition).toBeDefined(); expect(l._glyphs[0].billboard._clampedPosition).toBeDefined(); l.heightReference = HeightReference.NONE; expect(l._clampedPosition).toBeUndefined(); expect(l._glyphs[0].billboard._clampedPosition).toBeUndefined(); }); it("clears the billboard height reference callback when the label is removed", function () { scene.globe = createGlobe(); spyOn(scene.camera, "update"); var l = labelsWithHeight.add({ heightReference: HeightReference.CLAMP_TO_GROUND, text: "t", position: Cartesian3.fromDegrees(-72.0, 40.0), }); scene.renderForSpecs(); var billboard = l._glyphs[0].billboard; expect(billboard._removeCallbackFunc).toBeDefined(); var spy = spyOn(billboard, "_removeCallbackFunc"); labelsWithHeight.remove(l); expect(spy).toHaveBeenCalled(); expect( labelsWithHeight._spareBillboards[0]._removeCallbackFunc ).toBeUndefined(); }); }); }, "WebGL" );