Skip to content

Instantly share code, notes, and snippets.

@erhhung
Last active February 16, 2024 00:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erhhung/20b0119527b6b76a0f0e669fd1cfed78 to your computer and use it in GitHub Desktop.
Save erhhung/20b0119527b6b76a0f0e669fd1cfed78 to your computer and use it in GitHub Desktop.
Cesium Sandcastle Icon Scaling Issue
/*
* 1. open https://sandcastle.cesium.com/
* 2. paste this code into the editor
* 3. open debugger and disable cache
* 4. click Run and wait for globe
* 5. click "Run camera sequence"
*/
const URL = 'https://geotest{s}.ixstack.net/wms';
const LAYER = 'gvdl:eethnhgcjbwvsrwaqfsgyvzzkw';
const STYLE = 'gvdl:point';
const ICON = '//gvdldev1.ixstack.net/resources/images/MBLY_traffic_lightsX.svg';
const VIEWS = [
{bbox:[35.1776846357, 31.7591124942, 35.2591994373, 31.8057649301], delay:1},
{bbox:[35.2239844326, 31.7781897108, 35.2270145363, 31.7799243770], delay:5},
{bbox:[35.2031740007, 31.7863955220, 35.2046575848, 31.7872447724], delay:5},
];
const SUBDOMAINS = 3;
const wmsArgs = {
url: new Cesium.Resource({
url: URL,
headers: {
// NOTE: this Cesium Support access token expires on 2021-07-25
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6IjZ4eXBwbWo1ZG44aGtzNGozc2VldGozdGoyLmtpZCIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpZ3A6ZGV2MSIsImF1ZCI6IndtcyIsInN1YiI6IjJiMW5zd3l0Z2Y4cjBhcXJhODZ4NTdkeTNhLmFwcCIsImFwcCI6ImNlc2l1bS1zdXBwb3J0IiwiY29tIjoidzUxN2ZqZGtzODZldGFudzE4MjNkN3ZrNHcuY29tIiwianRpIjoiN2U4OHlmempwNTh3bnQ1eHZiZDdjd3dtdG4uanRpIiwiaWF0IjoxNjI0NjQwNDAwLCJleHAiOjE2MjcyMzI0MDB9.fpapCEwd5qm4Au-0dbHrB06ekn93DyBD_EvakISCdB4',
},
}),
subdomains: Array.from({length: SUBDOMAINS}, (v,i) => `${i+1}`),
layers: LAYER,
};
const params = {
tiled: true,
transparent: true,
format: 'image/png8',
//format_options: 'antialias:off',
styles: STYLE,
};
// https://www.cesium.com/docs/cesiumjs-ref-doc/WebMapServiceImageryProvider.html
const createProvider = opts => new Cesium.WebMapServiceImageryProvider({
...wmsArgs,
parameters: {
...params,
...opts,
},
getFeatureInfoParameters: {
// don't need all "params"
styles: STYLE,
...opts,
},
});
// env: takes array of sublayer tuples and optional
// property name (style defines default: "category")
const env = (subs, prop='') => (prop ? `prop:${prop};`:'') +
subs.map(([v,c,o,u],i) => `v${i}:${v}` +
`;c${i}:${c}` +
`;o${i}:${o}` +
(u ?`;u${i}:${u}`:'')).join(';');
const provider = createProvider({
env: env([
// [value, color, opacity, url]
['Unchanged','D4AEFA', 1, ICON],
['Changed', 'FFC887', 1, ICON],
['New', 'D9FF87', 1, ICON],
['Missing', 'FF7070', 1, ICON],
]),
});
// https://cesium.com/learn/cesiumjs/ref-doc/Viewer.html#.ConstructorOptions
const viewer = new Cesium.Viewer('cesiumContainer', {
geocoder: false,
sceneModePicker: false,
baseLayerPicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
});
// https://cesium.com/learn/cesiumjs/ref-doc/ImageryLayer.html
const layer = new Cesium.ImageryLayer(provider, {
// set zoom level below which layer is hidden
// this value doesn't appear to be adjustable
minimumTerrainLevel: 0,
});
viewer.imageryLayers.add(layer);
let timeout;
const debug = {
hideLayerDuringFlight: false,
};
function setCameraView(viewRect) {
// hide layer during the flyTo animation
layer.show = !debug.hideLayerDuringFlight;
// https://cesium.com/learn/cesiumjs/ref-doc/Camera.html#flyTo
viewer.camera.flyTo({
destination: viewRect,
complete: () => layer.show = true,
});
}
function flyToView(i=0) {
const {bbox,delay} = VIEWS[i];
timeout = setTimeout(() => {
setCameraView(Cesium.Rectangle.fromDegrees(...bbox));
const view = bbox.map(x => x.toFixed(10)).join(', ');
console.log(`Flying to VIEWS[${i}]: ${view}`);
if (VIEWS[i+1]) {
flyToView(i+1);
}
}, delay*1000);
}
function runSequence() {
const {camera} = viewer;
camera.cancelFlight();
if (timeout) {
camera.setView({destination: Cesium.Camera.DEFAULT_VIEW_RECTANGLE});
camera.zoomOut(8575000);
clearTimeout(timeout);
}
flyToView();
}
/*
* RENDER HUD AND CONTROLS
*/
document.getElementById('toolbar').outerHTML = `<div id="toolbar"/><div id="hud"/>`;
const hud = document.getElementById('hud');
// https://github.com/CesiumGS/cesium/blob/master/Apps/Sandcastle/Sandcastle-header.js
Sandcastle.addToolbarButton('Run camera sequence', runSequence);
Sandcastle.addToggleButton('Hide layer during flight', debug.hideLayerDuringFlight,
checked => debug.hideLayerDuringFlight = checked);
const elts = document.getElementsByClassName('cesium-button');
for (let i=0; i < elts.length; i++) {
// fix uneven button heights
elts[i].style.height = '28px';
}
// add thousands separators to number
const addSep = x => String(x).replace(/\B(?=(\d{3})+(?!\d))(?<!\..*)/g,',');
const LEVELS = Array.from({length: 24}, (v,i) => 156543.034 / 2**i); // m/px
function getCameraView() {
const rect = viewer.camera.computeViewRectangle();
const rads = []; Cesium.Rectangle.pack(rect, rads);
const degs = rads.map(r => Cesium.Math.toDegrees(r));
return degs.map(d => d.toFixed(10)).join(', ');
}
function getCameraPos() {
const posWC = viewer.camera.positionWC;
const carto = new Cesium.Cartographic();
const {ellipsoid} = viewer.scene.mapProjection;
ellipsoid.cartesianToCartographic(posWC, carto);
return {
lon: Cesium.Math.toDegrees(carto.longitude).toFixed(3),
lat: Cesium.Math.toDegrees(carto.latitude).toFixed(3),
alt: (carto.height / 1000).toFixed(3),
};
}
function getCameraZoom() {
const {ellipsoid} = viewer.scene.globe;
const {camera,canvas} = viewer.scene;
const {width:w, height:h} = canvas;
function getViewExt() {
const corners = [[0,0], [w,0], [0,h],[w,h]].map(p =>
camera.pickEllipsoid(new Cesium.Cartesian2(...p), ellipsoid)
);
if (corners.some(x => !x)) {
return Cesium.Rectangle.MAX_VALUE;
}
return Cesium.Rectangle.fromCartographicArray(
ellipsoid.cartesianArrayToCartographicArray(corners)
);
}
const extent = getViewExt();
if (extent.equals(Cesium.Rectangle.MAX_VALUE)) {
return {level:'?', scale:'∞'};
}
const diff = Math.abs(extent.north - extent.south);
const kmPerPixel = (diff * 6355.3) / canvas.clientHeight;
const mPerPixel = kmPerPixel * 1000;
const cmPerPixel = mPerPixel * 100;
const scale = cmPerPixel * 96 / 2.54;
return {
level: LEVELS.findIndex(r => mPerPixel > (r + r/2) / 2),
scale: addSep(scale.toFixed()),
};
}
// update HUD on clock ticks AND frame updates
viewer.clock.onTick.addEventListener(() => {
const view = getCameraView();
const {lon,lat,alt} = getCameraPos();
const {level,scale} = getCameraZoom();
const data = view + lon+lat+alt + level+scale;
if (data === hud.data) {
return;
}
hud.data = data;
hud.innerHTML = `<table>
<tr><th align=right>VIEW:</th><td>${view}</td></tr>
<tr><th>CAMERA:</th><td>lon ${lon}°, lat ${lat}°, alt ${alt} km</td></tr>
<tr><th align=right>ZOOM:</th><td>${level} (1:${scale})</td></tr>
</table>`;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment