UNPKG

mapillary-js

Version:

WebGL JavaScript library for displaying street level imagery from mapillary.com

647 lines (468 loc) 25.6 kB
import {take} from "rxjs/operators"; import { IPopupOffset, Popup, } from "../../../src/Component"; import {ViewportCoords} from "../../../src/Geo"; import {RenderCamera} from "../../../src/Render"; import {DOM} from "../../../src/Utils"; import {Alignment} from "../../../src/Viewer"; describe("Popup.ctor", () => { it("should be defined", () => { const popup: Popup = new Popup(); expect(popup).toBeDefined(); }); }); describe("Popup.changed$", () => { it("should notify change", (done: Function) => { const popup: Popup = new Popup(); popup.changed$.pipe( take(5)) .subscribe( (p: Popup): void => { expect(p).toBe(popup); }, undefined, (): void => { done(); }); popup.setBasicPoint([0.5, 0.5]); popup.setBasicRect([0.5, 0.5]); popup.setDOMContent(document.createElement("div")); popup.setHTML("<div></div"); popup.setText("text"); }); }); describe("Popup.update", () => { it("should add a .mapillaryjs-popup element", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup").length).toBe(1); }); it("should set mapillaryjs-popup-capture-pointer class by default", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-capture-pointer").length) .toBeGreaterThanOrEqual(1); }); it("should not set mapillaryjs-popup-capture-pointer class when disabled", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ capturePointer: false }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-capture-pointer").length).toBe(0); }); it("should translate to pixel value calculated from basic value", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const popup: Popup = new Popup({ float: Alignment.Center }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const transform: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.transform; expect(/translate\(40px,\s?60px\)/.test(transform)).toBe(true); }); it("should translate to pixel value calculated from basic when position is center for rect", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const popup: Popup = new Popup({ position: Alignment.Center }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.3, 0.5, 0.5, 0.7]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const transform: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.transform; expect(/translate\(40px,\s?60px\)/.test(transform)).toBe(true); }); it("should be visible if in front of camera", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const popup: Popup = new Popup({ float: Alignment.Center }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const display: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.display; expect(display).toBe(""); }); it("should not be visible if behind camera", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue(null); const popup: Popup = new Popup({ float: Alignment.Center }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const display: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.display; expect(display).toBe("none"); }); it("should float to top when float is automatic", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-top").length) .toBe(1); }); }); describe("Popup.setText", () => { it("should set content", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").textContent).toBe("Test"); }); it("should protect against XSS", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("<script>alert('XSS')</script>"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").textContent) .toBe("<script>alert('XSS')</script>"); }); }); describe("Popup.setHTML", () => { it("should set content", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setHTML("<span>Test</span>"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").innerHTML) .toBe("<span>Test</span>"); }); }); describe("Popup.setDOMContent", () => { it("should set content", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); const content: HTMLSpanElement = document.createElement("span"); popup.setDOMContent(content); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").firstChild) .toEqual(content); }); it("should overwrite previous content", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup(undefined, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test 1"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").textContent) .toBe("Test 1"); popup.setHTML("Test 2"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").textContent) .toBe("Test 2"); popup.setDOMContent(document.createTextNode("Test 3")); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelector(".mapillaryjs-popup-content").textContent) .toBe("Test 3"); }); }); describe("Popup.float", () => { it("should float as specified by the float option", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ float: Alignment.TopLeft }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-top-left").length) .toBe(1); }); it("should not have a tip if floating to center", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ float: Alignment.Center }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-tip").length).toBe(0); }); it("should have a tip if not floating to center", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ float: Alignment.Bottom }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-tip").length).toBe(1); }); it("should float in direction of position for rect", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ position: Alignment.BottomRight }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-bottom-right").length) .toBe(1); }); }); describe("Popup.setBasicRect", () => { let dom: DOM; let viewportCoords: ViewportCoords; let basicToCanvasSafeSpy: jasmine.Spy; beforeEach(() => { dom = new DOM(); const createElement: Function = dom.createElement.bind(dom); function createTagMappedElement<K extends keyof HTMLElementTagNameMap>( tagName: K, className?: string, container?: HTMLElement): HTMLElementTagNameMap[K] { if (className === "mapillaryjs-popup") { const element: HTMLDivElement = window.document.createElement("div"); Object.defineProperty(element, "offsetWidth", { value: 20 }); Object.defineProperty(element, "offsetHeight", { value: 20 }); if (!!className) { element.className = className; } if (!!container) { container.appendChild(element); } return <HTMLElementTagNameMap[K]>element; } return createElement(tagName, className, container); }; spyOn(dom, "createElement").and.callFake(createTagMappedElement); viewportCoords = new ViewportCoords(); basicToCanvasSafeSpy = spyOn(viewportCoords, "basicToCanvasSafe").and.callFake( (basicX: number, basicY: number): number[] => { // if basic X has been wrapped over pano border // interpret as if it was centered horizontally. basicX = basicX > 1 ? 0.5 : basicX; return [100 * basicX, 100 * basicY]; }); }); it("should get default top position", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.25, 0.25, 0.75, 0.75]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-top").length) .toBe(1); }); it("should get bottom position when not completely visible on top", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.25, 0.1, 0.75, 0.75]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-bottom").length) .toBe(1); }); it("should get left position when not completely visible on top or bottom", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.25, 0.1, 0.75, 0.9]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-left").length) .toBe(1); }); it("should get right position when not completely visible on top, bottom or left", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.1, 0.1, 0.75, 0.9]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-right").length) .toBe(1); }); it("should get position with largest area visible", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.15, 0.1, 0.9, 0.9]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-left").length) .toBe(1); }); it("should shift basic x when rect is wrapping pano border", () => { const popup: Popup = new Popup({}, viewportCoords, dom); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicRect([0.9, 0.4, 0.2, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100 }, undefined); expect(basicToCanvasSafeSpy.calls.count()).toBe(1); expect(basicToCanvasSafeSpy.calls.first().args[0]).toBe(1.05); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-float-top").length) .toBe(1); }); }); describe("Popup.opacity", () => { it("should have opacity as specified by the opacity option", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ opacity: 0.5 }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const opacity: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")) .style.opacity; expect(opacity).toBe("0.5"); }); }); describe("Popup.offset", () => { it("should offset in the float direction", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const popup: Popup = new Popup({ offset: 12, float: Alignment.Right }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const transform: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.transform; expect(/translate\(52px,\s?60px\)/.test(transform)).toBe(true); }); it("should offset according to popup offset struct in the float direction", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const offset: IPopupOffset = { bottom: [0, 1], bottomLeft: [2, 3], bottomRight: [4, 5], center: [6, 7], left: [8, 9], right: [10, 11], top: [12, 13], topLeft: [14, 15], topRight: [16, 17], }; const popup: Popup = new Popup({ offset: offset, float: Alignment.TopLeft }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const transform: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.transform; expect(/translate\(54px,\s?75px\)/.test(transform)).toBe(true); }); it("should offset left and up for negative popup offset struct values in the float direction", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([40, 60]); const offset: IPopupOffset = { bottom: [-0, -1], bottomLeft: [-2, -3], bottomRight: [-4, -5], center: [-6, -7], left: [-8, -9], right: [-10, -11], top: [-12, -13], topLeft: [-14, -15], topRight: [-16, -17], }; const popup: Popup = new Popup({ offset: offset, float: Alignment.BottomRight }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.4, 0.6]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); const transform: string = (<HTMLElement>parentContainer.querySelector(".mapillaryjs-popup")).style.transform; expect(/translate\(36px,\s?55px\)/.test(transform)).toBe(true); }); }); describe("Popup.clean", () => { it("should be clean if specified by clean option", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ clean: true }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-content-clean").length).toBe(1); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-content").length).toBe(0); }); it("should not be clean if not specified by clean option", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({}, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-content-clean").length).toBe(0); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-content").length).toBe(1); }); it("should not have a tip if clean", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ clean: true }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-tip").length).toBe(0); }); it("should have a tip if not clean", () => { const viewportCoords: ViewportCoords = new ViewportCoords(); spyOn(viewportCoords, "basicToCanvasSafe").and.returnValue([50, 50]); const popup: Popup = new Popup({ clean: false }, viewportCoords); const parentContainer: HTMLElement = document.createElement("div"); popup.setParentContainer(parentContainer); popup.setBasicPoint([0.5, 0.5]); popup.setText("Test"); popup.update(<RenderCamera>{}, { height: 100, width: 100}, undefined); expect(parentContainer.querySelectorAll(".mapillaryjs-popup-tip").length).toBe(1); }); });