control/DebugInfo.tstypescript
import { Control, type IControlParams } from "./Control";
import { Dialog } from "../ui/Dialog";
import { ToggleButton } from "../ui/ToggleButton";
import { GlobusTerrain } from "../terrain/GlobusTerrain";
import { CanvasTiles } from "../layer/CanvasTiles";
import { DEGREES } from "../math";
const ICON_LOCK_BUTTON_SVG = `<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="-7.5 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>lock</title>
<path d="M14.625 15.156h2.094c0.281 0 0.5 0.25 0.5 0.531v11c0 0.281-0.219 0.5-0.5 0.5h-16.219c-0.281 0-0.5-0.219-0.5-0.5v-11c0-0.281 0.219-0.531 0.5-0.531h2.031v-5.125c0-2.875 1.844-5.25 4.688-5.25h2.688c2.875 0 4.719 2.375 4.719 5.25v5.125zM5.188 15.156h6.813v-4.875c0-1.594-1.313-2.938-2.938-2.938h-0.969c-1.594 0-2.906 1.344-2.906 2.938v4.875zM7.156 24h2.906l-0.719-3.156c0.5-0.25 0.844-0.781 0.844-1.375 0-0.906-0.719-1.594-1.594-1.594s-1.563 0.688-1.563 1.594c0 0.594 0.344 1.125 0.844 1.375z"></path>
</svg>`;
const ICON_BUTTON_SVG = `<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
\t width="800px" height="800px" viewBox="0 0 932.179 932.179"
\t xml:space="preserve">
<g>
\t<path d="M61.2,341.538c4.9,16.8,11.7,33,20.3,48.2l-24.5,30.9c-8,10.1-7.1,24.5,1.9,33.6l42.2,42.2c9.1,9.1,23.5,9.899,33.6,1.899
\t\tl30.7-24.3c15.8,9.101,32.6,16.2,50.1,21.2l4.6,39.5c1.5,12.8,12.3,22.4,25.1,22.4h59.7c12.8,0,23.6-9.601,25.1-22.4l4.4-38.1
\t\tc18.8-4.9,36.8-12.2,53.7-21.7l29.7,23.5c10.1,8,24.5,7.1,33.6-1.9l42.2-42.2c9.1-9.1,9.9-23.5,1.9-33.6l-23.1-29.3
\t\tc9.6-16.601,17.1-34.3,22.1-52.8l35.6-4.1c12.801-1.5,22.4-12.3,22.4-25.1v-59.7c0-12.8-9.6-23.6-22.4-25.1l-35.1-4.1
\t\tc-4.801-18.3-12-35.8-21.199-52.2l21.6-27.3c8-10.1,7.1-24.5-1.9-33.6l-42.1-42.1c-9.1-9.1-23.5-9.9-33.6-1.9l-26.5,21
\t\tc-17.2-10.1-35.601-17.8-54.9-23l-4-34.3c-1.5-12.8-12.3-22.4-25.1-22.4h-59.7c-12.8,0-23.6,9.6-25.1,22.4l-4,34.3
\t\tc-19.8,5.3-38.7,13.3-56.3,23.8l-27.5-21.8c-10.1-8-24.5-7.1-33.6,1.9l-42.2,42.2c-9.1,9.1-9.9,23.5-1.9,33.6l23,29.1
\t\tc-9.2,16.6-16.2,34.3-20.8,52.7l-36.8,4.2c-12.8,1.5-22.4,12.3-22.4,25.1v59.7c0,12.8,9.6,23.6,22.4,25.1L61.2,341.538z
\t\t M277.5,180.038c54.4,0,98.7,44.3,98.7,98.7s-44.3,98.7-98.7,98.7c-54.399,0-98.7-44.3-98.7-98.7S223.1,180.038,277.5,180.038z"/>
\t<path d="M867.699,356.238l-31.5-26.6c-9.699-8.2-24-7.8-33.199,0.9l-17.4,16.3c-14.699-7.1-30.299-12.1-46.4-15l-4.898-24
\t\tc-2.5-12.4-14-21-26.602-20l-41.1,3.5c-12.6,1.1-22.5,11.4-22.9,24.1l-0.799,24.4c-15.801,5.7-30.701,13.5-44.301,23.3
\t\tl-20.799-13.8c-10.602-7-24.701-5-32.9,4.7l-26.6,31.7c-8.201,9.7-7.801,24,0.898,33.2l18.201,19.399
\t\tc-6.301,14.2-10.801,29.101-13.4,44.4l-26,5.3c-12.4,2.5-21,14-20,26.601l3.5,41.1c1.1,12.6,11.4,22.5,24.1,22.9l28.1,0.899
\t\tc5.102,13.4,11.801,26.101,19.9,38l-15.699,23.7c-7,10.6-5,24.7,4.699,32.9l31.5,26.6c9.701,8.2,24,7.8,33.201-0.9l20.6-19.3
\t\tc13.5,6.3,27.699,11,42.299,13.8l5.701,28.2c2.5,12.4,14,21,26.6,20l41.1-3.5c12.6-1.1,22.5-11.399,22.9-24.1l0.9-27.601
\t\tc15-5.3,29.199-12.5,42.299-21.399l22.701,15c10.6,7,24.699,5,32.9-4.7l26.6-31.5c8.199-9.7,7.799-24-0.9-33.2l-18.301-19.399
\t\tc6.701-14.2,11.602-29.2,14.4-44.601l25-5.1c12.4-2.5,21-14,20-26.601l-3.5-41.1c-1.1-12.6-11.4-22.5-24.1-22.9l-25.1-0.8
\t\tc-5.201-14.6-12.201-28.399-20.9-41.2l13.699-20.6C879.4,378.638,877.4,364.438,867.699,356.238z M712.801,593.837
\t\tc-44.4,3.801-83.602-29.3-87.301-73.699c-3.801-44.4,29.301-83.601,73.699-87.301c44.4-3.8,83.602,29.301,87.301,73.7
\t\tC790.301,550.938,757.199,590.138,712.801,593.837z"/>
\t<path d="M205,704.438c-12.6,1.3-22.3,11.899-22.4,24.6l-0.3,25.3c-0.2,12.7,9.2,23.5,21.8,25.101l18.6,2.399
\t\tc3.1,11.301,7.5,22.101,13.2,32.301l-12,14.8c-8,9.899-7.4,24.1,1.5,33.2l17.7,18.1c8.9,9.1,23.1,10.1,33.2,2.3l14.899-11.5
\t\tc10.5,6.2,21.601,11.101,33.2,14.5l2,19.2c1.3,12.6,11.9,22.3,24.6,22.4l25.301,0.3c12.699,0.2,23.5-9.2,25.1-21.8l2.3-18.2
\t\tc12.601-3.101,24.601-7.8,36-14l14,11.3c9.9,8,24.101,7.4,33.201-1.5l18.1-17.7c9.1-8.899,10.1-23.1,2.301-33.2L496.6,818.438
\t\tc6.6-11,11.701-22.7,15.201-35l16.6-1.7c12.6-1.3,22.299-11.9,22.4-24.6l0.299-25.301c0.201-12.699-9.199-23.5-21.799-25.1
\t\tl-16.201-2.1c-3.1-12.2-7.699-24-13.699-35l10.1-12.4c8-9.9,7.4-24.1-1.5-33.2l-17.699-18.1c-8.9-9.101-23.102-10.101-33.201-2.3
\t\tl-12.101,9.3c-11.399-6.9-23.6-12.2-36.399-15.8l-1.601-15.7c-1.3-12.601-11.899-22.3-24.6-22.4l-25.3-0.3
\t\tc-12.7-0.2-23.5,9.2-25.101,21.8l-2,15.601c-13.199,3.399-25.899,8.6-37.699,15.399l-12.5-10.2c-9.9-8-24.101-7.399-33.201,1.5
\t\tl-18.2,17.801c-9.1,8.899-10.1,23.1-2.3,33.199l10.7,13.801c-6.2,11-11.1,22.699-14.3,35L205,704.438z M368.3,675.837
\t\tc36.3,0.4,65.399,30.301,65,66.601c-0.4,36.3-30.301,65.399-66.601,65c-36.3-0.4-65.399-30.3-65-66.601
\t\tC302.1,704.538,332,675.438,368.3,675.837z"/>
</g>
</svg>`;
const ICON_CANVASTILES_SVG = `<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M 4 4 L 4 8 L 8 8 L 8 4 L 4 4 z M 10 4 L 10 8 L 14 8 L 14 4 L 10 4 z M 16 4 L 16 8 L 20 8 L 20 4 L 16 4 z M 4 10 L 4 14 L 8 14 L 8 10 L 4 10 z M 10 10 L 10 14 L 14 14 L 14 10 L 10 10 z M 16 10 L 16 14 L 20 14 L 20 10 L 16 10 z M 4 16 L 4 20 L 8 20 L 8 16 L 4 16 z M 10 16 L 10 20 L 14 20 L 14 16 L 10 16 z M 16 16 L 16 20 L 20 20 L 20 16 L 16 16 z"/>
</svg>`;
export interface IDebugInfoWatch {
label: string;
valEl?: HTMLElement;
frame?: () => string | number;
}
interface IDebugInfoParams extends IControlParams {
watch?: IDebugInfoWatch[];
}
export class DebugInfo extends Control {
public el: HTMLElement | null;
protected _watch: IDebugInfoWatch[];
protected _toggleBtn: ToggleButton;
protected _dialog: Dialog<null>;
protected _canvasTiles: CanvasTiles;
protected _drawnFrames: number;
constructor(options: IDebugInfoParams = {}) {
if (!options.name || options.name === "") {
options.name = "DebugInfo";
}
super(options);
this.el = null;
this._watch = options.watch || [];
this._drawnFrames = 0;
this._toggleBtn = new ToggleButton({
classList: ["og-map-button", "og-debuginfo_button"],
icon: ICON_BUTTON_SVG
});
this._dialog = new Dialog({
title: "Debug Info",
visible: false,
useHide: true,
top: 120,
left: 60,
width: 480
});
this._dialog.events.on("visibility", (v: boolean) => {
this._toggleBtn.setActive(v);
});
this._canvasTiles = new CanvasTiles("Tile grid", {
visibility: true,
isBaseLayer: false,
hideInLayerSwitcher: true,
drawTile: function (material: any, applyCanvas: any) {
//
// This is important create canvas here!
//
let cnv = document.createElement("canvas");
let ctx = cnv.getContext("2d")!;
cnv.width = 256;
cnv.height = 256;
//Clear canvas
ctx.clearRect(0, 0, cnv.width, cnv.height);
//Draw border
ctx.beginPath();
ctx.rect(0, 0, cnv.width, cnv.height);
ctx.lineWidth = 2;
ctx.strokeStyle = "black";
ctx.stroke();
let size;
// if (material.segment.isPole) {
// let ext = material.segment.getExtentLonLat();
//
// ctx.fillStyle = 'black';
// ctx.font = 'normal ' + 29 + 'px Verdana';
//
// ctx.textAlign = 'center';
// ctx.fillText(`${ext.northEast.lon.toFixed(3)} ${ext.northEast.lat.toFixed(3)}`, cnv.width / 2, cnv.height / 2 + 20);
// ctx.fillText(`${ext.southWest.lon.toFixed(3)} ${ext.southWest.lat.toFixed(3)}`, cnv.width / 2, cnv.height / 2 - 20);
// } else {
//Draw text
if (material.segment.tileZoom > 14) {
size = "26";
} else {
size = "32";
}
ctx.fillStyle = "black";
ctx.font = "normal " + size + "px Verdana";
ctx.textAlign = "center";
ctx.fillText(
material.segment.tileX + "," + material.segment.tileY + "," + material.segment.tileZoom,
cnv.width / 2,
cnv.height / 2
);
//}
//Draw canvas tile
applyCanvas(cnv);
}
});
}
public addWatches(watches: IDebugInfoWatch[]) {
for (let i = 0; i < watches.length; i++) {
this.addWatch(watches[i]);
}
}
public addWatch(watch: IDebugInfoWatch) {
this._watch.push(watch);
let watchEl = document.createElement("div");
watchEl.classList.add("og-watch-line");
watchEl.innerHTML = `<div class="og-watch-label">${watch.label}</div><div class="og-watch-value"></div>`;
watch.valEl = watchEl.querySelector<HTMLElement>(".og-watch-value")!;
this.el!.appendChild(watchEl);
}
public override oninit() {
this._toggleBtn.appendTo(this.renderer!.topLeftContainer());
this._dialog.appendTo(this.renderer!.getUIContainer());
this._dialog.events.on("visibility", (v: boolean) => {
if (v) {
this._dialog.positionNearElementOnFirstOpen(this._toggleBtn.el, this.renderer!.getUIContainer());
}
});
this._toggleBtn.events.on("change", (isActive: boolean) => {
this._dialog.setVisibility(isActive);
});
this.el = document.createElement("div");
this.el.className = "og-debug-info";
let $controls = document.createElement("div");
$controls.classList.add("og-debuginfo_controls");
this.el.appendChild($controls);
let temp = this._watch;
this._watch = [];
for (let i = 0; i < temp.length; i++) {
this.addWatch(temp[i]);
}
this._dialog.container?.appendChild(this.el);
this.renderer!.events.on("predraw", this._frame, this);
this.addWatch({
label: "Drawn frames",
frame: () => this._drawnFrames
});
let p = this.planet!;
if (p) {
this.addWatches([
{
label: "Nodes count",
frame: () => p!.quadTreeStrategy._renderedNodes.length
},
{
label: "Planet._fadingNodes",
frame: () => p.quadTreeStrategy._fadingNodes.size
},
{
label: "createdNodes",
frame: () => p._createdNodesCount
},
{
label: "indexesCache",
frame: () => p._indexesCacheToRemoveCounter
},
{
label: "distBeforeMemClear",
frame: () => Math.round(p._distBeforeMemClear)
},
{
label: "maxZoom/minZoom",
frame: () => p.quadTreeStrategy.maxCurrZoom + " / " + p?.quadTreeStrategy.minCurrZoom
},
{
label: "viewExtent",
frame: () => p.getViewExtent().toString()
},
{
label: "Mouse distance, m",
frame: () => {
let cart = p.getCartesianFromMouseTerrain();
if (cart) {
return p.camera.eye.distance(cart).toFixed(3);
}
return "";
}
},
{
label: "lodSize",
frame: () => Math.round(p.quadTreeStrategy.lodSize)
},
{
label: "deltaTime/FPS",
frame: () =>
`<div style="width:70px"><div style="width:20px; float: left;">
${Math.round(p.renderer!.handler.deltaTime)}
</div> <div style="float: left">
${Math.round(1000.0 / p.renderer!.handler.deltaTime)}
</div></div>`
},
{
label: "-------------------------"
},
{
label: "Pitch, deg",
frame: () => (p.camera.getPitch() * DEGREES).toFixed(2)
},
{
label: "Yaw, deg",
frame: () => (p.camera.getYaw() * DEGREES).toFixed(2)
},
{
label: "Roll, deg",
frame: () => (p.camera.getRoll() * DEGREES).toFixed(2)
},
{
label: "Lon, Lat",
frame: () =>
`<div style="width:190px">${p.camera._lonLat.lon.toFixed(7)}, ${p.camera._lonLat.lon.toFixed(7)}</div>`
},
{
label: "height/alt, m",
frame: () =>
`<div style="width:190px">${
p.camera._lonLat.height.toFixed(2) + " / " + p.camera.getAltitude().toFixed(2)
}</div>`
},
{
label: "cam.slope",
frame: () => p.camera.slope.toFixed(3)
},
{
label: "-------------------------"
},
{
label: "_renderCompleted / renderCompletedActivated",
frame: () =>
`${p.quadTreeStrategy._renderCompleted} / ${p.quadTreeStrategy._renderCompletedActivated}`
},
{
label: "_terrainCompleted / terrainCompletedActivated",
frame: () =>
`${p.quadTreeStrategy._terrainCompleted} / ${p.quadTreeStrategy._terrainCompletedActivated}`
},
{
label: "PlainWorker",
frame: () => p._plainSegmentWorker.pendingQueue.length
},
{
label: "TileLoader",
frame: () => `${p._tileLoader.loading} ${p._tileLoader.queue.length}`
},
{
label: "TerrainLoader",
frame: () => {
if (p.terrain && !p.terrain.isEmpty) {
return `${(p.terrain as GlobusTerrain).loader.loading} ${(p.terrain as GlobusTerrain).loader.queue.length}`;
}
return "";
}
},
{
label: "TerrainWorker",
frame: () => p._terrainWorker.pendingQueue.length
},
{
label: "NormalMapCreator",
frame: () => p._normalMapCreator.queueSize
},
{
label: "VectorTileCreator",
frame: () => p._vectorTileCreator.queueSize
}
]);
}
let lockTreeBtn = new ToggleButton({
classList: ["og-debuginfo_controls-button"],
icon: ICON_LOCK_BUTTON_SVG,
title: "Lock/Unlock quad tree"
});
lockTreeBtn.appendTo($controls);
lockTreeBtn.events.on("change", (isActive: boolean) => {
if (isActive) {
p.lockQuadTree();
} else {
p.unlockQuadTree();
}
});
let canvasTilesBtn = new ToggleButton({
classList: ["og-debuginfo_controls-button"],
icon: ICON_CANVASTILES_SVG,
title: "Show/Hide grid"
});
canvasTilesBtn.appendTo($controls);
canvasTilesBtn.events.on("change", (isActive: boolean) => {
if (isActive) {
this.planet!.addLayer(this._canvasTiles);
} else {
this._canvasTiles.remove();
}
});
}
protected _frame() {
this._drawnFrames++;
this._watch.forEach((w) => {
if (w.valEl) {
w.valEl.innerHTML = w.frame ? String(w.frame()) : "";
}
});
}
}