On Wednesday, May 15, 2019 at 9:15:13 AM UTC-4, Omar Shehata wrote:
> Thanks for the additional explanation and screenshots. I can definitely see how this would be helpful especially if you have specific data attached to each that becomes visible on click. I think you can actually use CesiumJS's clustering to do this, since it will already cluster icons in one icon, then you just need to make it so that when you click on that clustered icon, it expands out and "declusters".
>
>
>
> If you can put together a Sandcastle (
https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/) code sample of what you've got so far, I can give it a shot and see if there's an easy way to "expand on click" like that in Cesium. If it's not so trivial after all, we can open a feature request on GitHub for it.
>
> On Monday, May 13, 2019 at 10:15:28 AM UTC-4,
john....@gmail.com wrote:On Monday, May 13, 2019 at 9:46:50 AM UTC-4, Omar Shehata wrote:
> > Clustering is supposed to help with that in that it communicates there's this many icons in that location that become visible when zoomed in enough. I think it was designed this way to keep the icons from moving from their locations on the globe since an accurate location is often part of the information it presents.
> >
> >
> > Having a "spread" option might be interesting though. Does it spread out the icons to make them all visible, no matter how far away it goes from the center point? This might be an interesting feature request to open an issue for on GitHub (
https://github.com/AnalyticalGraphicsInc/cesium/issues) with a bit more detail on the use case and see if other developers would find this useful in their applications.
> >
> I didn't like to use clustering as an example, since clustering takes a large amount of icons in a geographic area and represents them as a single icon. What google earth does in this case, is that if you have a KML feed that has placemarks that are too close to render their respective icons individually, it has a single click event that will break them out from the point of over in a circle around the cursor with lines so it is possible to click on each individual icon in the "stack". It is a very useful feature because obviously, if you have too many entities in one spot there is no way to know how many you have or no way to see the infoboxes if data about those entities which are buried under each other with Vanilla cesium.
> I've been re-creating the Google Earth client interface piece by piece in Cesium so that I have ways to work-around this (Such as displaying the list of placemarks / entities in a left window pane and being able to click on them and zoom to them that way ) but this is one of the "nice to have" features that I can't seem to figure out how to do yet.
> Example :
> Here I have three placemarks, all in the same spot in google earth. It shows them all with 1 icon. When I click on it though, it spreads them out so I can see there are actually 3 hidden there.
As far as the workaround I'm currently using, I do something like GE and display a list of all of the Placemarks that I can navigate to. Since I can't paste the code directly, I'll just re-create an example:
I'm sure I left some stuff out, including HTML, CSS, and some javascript.. but basically you select some KML feeds from a radio list. (Feeds are hard-coded in this case. Google Earth would let you load them dynamically of course) When you select a feed, it would gray out the screen and say "LOADING" while the data source loads, and then that would go away when the promise is completed. The placemarks would be displayed (In a div not shown due to missing html) as well as on the globe, by their name and snippet (similar to google earth) and if you click on them from that list it would zoom to them on the map. This is how you could get around the overlapping icon issue.
-----------------
var radios = document.querySelectorAll('input[type=radio][name="feeds"]');
var loadInd = document.getElementById('loadingIndicator'); //loading display
Array.prototype.forEach.call(radios, function(radio) {
radio.addEventListener('change', changeHandler);
});
function changeHandler(event) {
resetDS();
cleanUI();
if ( this.value === 'myfeed' ) { // doesn't have to be static
viewer.selectedEntity = null; // close any infobox
loadInd.style.display = 'block'; //display loading div
viewer.dataSources.add(Cesium.KmlDataSource.load('myfeed.kml', {
camera: viewer.scene.camera,
canvas: viewer.scene.canvas,
clampToGround: false
})).then(
function (kmlData) {
parseEntities(kmlData.entities);
loadInd.style.display = 'none'; //remove loading div
viewer.flyTo(kmlData.entities);
});
}
}
//Removes all kml datasources
function resetDS() {
viewer.dataSources.removeAll();
}
//Removes all entities in the list
function cleanUI() {
var kmlDiv = document.getElementById('kmlDiv");
while (kmlDiv.firstChild) {
kmlDiv.removeChild(kmlDiv.lastChild);
}
}
//Lists all KML entities
//This isn't perfect, since KML folder structure can vary. You may have
//placemarks that have points AND polygons, or the first couple of elements
//in the list could be the name of the KML feed itself, or the title of the
//list of placemarks, etc.
function parseEntities(entities) {
var e;
var values = entities.values;
var docU = document.getElementById("kmlDiv");
var dl = document.createElement("dl"); //description list
//To make this like google earth, this should be a checkbox list so each
//placemark can be turned on and off
//I am aware loop starts at 0. Spot 0 was my KML document name so I did
//not include it, and spot 1 is actually my KML folder name before my
//placemark list in my "myfeed.kml"
for (var i = 1; i < values.length; i++) {
e = values[i];
if (Cesium.defined(e.position)) { {
// Does the Placemark have a Point - All of my examples had a Point
// AND a Polygon of just a single point value. Something to keep in
// mind that you may need to check for as you might get duplicates!
var dt = document.createElement("dt"); //create List Element
dt.setAttribute("class","underline"text"); //css to let user know it is clickable
dt.snippet = (e._kml.snippet); //should check if this exists first
dt.textContent =
e.name;
dt.description = e.description;
var dd = document.createElement("dd"); //create sublist for snippets
dd.textContent = dt.snippet;
dt.addEventListener("click", function() {
var date = new Date();
viewer.selectedEntity = null; // clear any info box that might be up
viewer.camera.flyTo({
destination: this.position.getValue(Cesium.JulianDate.fromDate(date)),
duration:0,
complete:function() {
viewer.camera.moveForward(-1000);
}
});
viewer.selectedEntity = this;
});
dl.appendChild(dt);
dl.appendChild(dd);
}
else {
// If not a position value
// ... leaving out code here
}
}