process CZML into 'viewer' from AJAX request

Hi all,

I would like to add a ‘highlight’ feature to my project on the Battle for Normandy.

You see that upon selecting a unit, the infoBox for that unit opens and displays descriptive content for that unit. The database includes information about the unit hierarchy (the family tree, aka order of battle).

I would also like to have, upon the same click-event, all of the child units be identified by a translucent ellipse centered at the origin of each child model. The resulting effect would be to highlight the connection between an adult, its child, its grandchildren, etc.

I currently access the infoBox via AJAX. I am trying to use AJAX again to handle this highlight feature. FYI- the database recurses to create the hierarchy and then queries the hierarchy to get the cartographicDegrees for the ellipses.

I have run into two issues:

1- is there an approach to use other than AJAX to dynamically add data to a running animation?

2- lacking a compelling “YES” to the first question, what is the best way to return the CZML code from the AJAX success function so that it is immediately added to (or processed into) the existing ‘viewer’?

I’ll build upon a Sandcastle I made several weeks ago to illustrate the challenge. It isn’t exactly the same, but is similar…

var viewer = new Cesium.Viewer(‘cesiumContainer’);
var scene = viewer.scene;

//------ create CZML ------

var czml =
[{“id” : “document”,
“version” : “1.0”
},{“id” : “Boston”,
“label”:{“text”:“Boston”},
“position”:{“cartographicDegrees”:[-71.0589,42.3601,0]},
“description”:“Boston is a city…”,
},{“id” : “New York City”,
“label”:{“text”:“New York”},
“description”:“New York is a city…”,
“position”:{“cartographicDegrees”:[-74.0059,40.7127,0]},
}];

var promise = Cesium.CzmlDataSource.load(czml);
promise.then(function(dataSource) {
viewer.dataSources.add(dataSource);

//------ Get the array of entities
var entities = dataSource.entities.values;
//------ Loop entities
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
var name = entity.label;
entity.label.translucencyByDistance = new Cesium.NearFarScalar(100000,1.0,500000,0.0);
}
}).otherwise(function(error){
//------ Display error
window.alert(error);
});

//------ Use JQuery/AJAX to update to current description

var handlerA = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handlerA.setInputAction(function(click) {
var pickedObject = scene.pick(click.position);
if (Cesium.defined(pickedObject)) {
$.ajax({
async: false,
type: ‘GET’,
url: ‘addCzml2.php’,
data: (pickedObject.id.id).val(),
success: function(data) {
czmlDataSource.process(data);
}
});
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

``

PHP File <<addCzml2.php>>

<?php ?>

``

Happy to try and clarify as necessary, Erik

STOP RIGHT THERE!

Me again.

Working on this challenge last night was making me crazy. I realize this morning that I was trying to do something crazy, and unnecessary, etc… Freshman mistake? I’ll grade that a sophomore mistake because at least I now know when I’ve gone and done something foolish.

There is no need to use AJAX for this operation. I will work on a couple of things and follow-up.

Cheers, erik

A software developer’s three best aids for debugging and solving problems:

  1. Sleep
  2. The shower
  3. A rubber duck

:slight_smile:

Mark, I tried sleep and a shower… I feel great, but I am still on the wrong course.

To summarize my message from above, I am trying to load a dataSource that I have created in an AJAX request to php. All sides of this operation function beautifully, except when I want them to function in unison! From the AJAX call I am getting an error “403 Forbidden, Cesium.js 447,” but if I run the exact same AJAX call but load a separate php file that contains only the result of the first php file, it works perfectly.

So using the code above as a starting point:

var viewer = new Cesium.Viewer(‘cesiumContainer’);
var scene = viewer.scene;

var czml =
[{“id” : “document”,
“version” : “1.0”
},{“id” : “Boston”,
“label”:{“text”:“Boston”},
“position”:{“cartographicDegrees”:[-71.0589,42.3601,0]},
“description”:“Boston is a city…”,
},{“id” : “New York City”,
“label”:{“text”:“New York”},
“description”:“New York is a city…”,
“position”:{“cartographicDegrees”:[-74.0059,40.7127,0]},
}];

dataSourceCollection = new Cesium.DataSourceCollection;
var promise = Cesium.CzmlDataSource.load(czml);
promise.then(function(dataSource) {
viewer.dataSources.add(dataSourceCollection.add(dataSource));
});

``

Now, to add Phili to the view, I call the server with php using $AJAX in a callback function, like so:

(document).ready(function(){ var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); handler.setInputAction(function(click) { var mousePick = scene.pick(click.position); if (Cesium.defined(mousePick)) { function getData() { return .ajax({
type: ‘GET’,
url: ‘hierarchy.php’,
data: ‘unitId=’ + (mousePick.id.id),
});
}
function processData(data) {
alert(data); //quick check for accurate czml formating
var mouseDataSource = new Cesium.CzmlDataSource.load(data);
mouseDataSource.then(function(dataSource) {
viewer.dataSources.add(dataSourceCollection.add(dataSource));
});
};
getData().done(processData);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
});

``

For this test I am forcing the call to ‘hierarchy.php’ to output the following:

[{“id” : “document”,“version” : “1.0”},
{“id” : “Philadelphia”,
“label”:{“text”:“Philadelphia”},
“position”:{
“cartographicDegrees”:[-75.169,39.966,0]
},
“description”:“Phili is a city…”,
}]

``

A couple of notes here. First, this code works perfectly if I run the hierarchy.php manually, save the output as ‘phili.php’, and then replace .load(data) with .load(‘phili.php’) in the following line:

var mouseDataSource = new Cesium.CzmlDataSource.load(data)

``

This suggests to me that the php is pulling properly, and that the javascript code here works properly.

Upon running the script I get an error that reads:

GET http://www.geo-animate.com/myFileStructure/[czml code written out here] 403 (Forbidden) Cesium.js:427.

Okay, so thinking the error was due to the size of the GET call in the AJAX request, I changed it to a POST request and it still returns the same >GET error.

I am happy to clarify any confusing points if someone is willing to hazard a guess.

Best, Erik

Friday, October 9, 2015 at 5:25:23 PM UTC+2, Mark Erikson wrote:

The AJAX call is passing a string into processData. If you pass a string to CzmlDataSource.load, it assumes it’s a URL and tries to load it. You need to parse the JSON into an actual object using JSON.parse.

Alternatively you can get rid of the call to $.ajax and simply build the URL to hierarchy.php with the appropriate query string, and pass the URL directly to CzmlDataSource.load.

Cheers, Scott. Two things. For any with the same problem, here is the .js with JSON.parse as Scott suggested:

(document).ready(function(){ var handlerB = new Cesium.ScreenSpaceEventHandler(scene.canvas); handlerB.setInputAction(function(click) { var hierarchyPick = scene.pick(click.position); if (Cesium.defined(hierarchyPick)) { function getData() { return .ajax({
type: ‘POST’,
url: ‘hierarchy.php’,
data: ‘unitId=’ + (hierarchyPick.id.id),
});
}
function processData(data) {
var hierDataSource = new Cesium.CzmlDataSource.load(JSON.parse(data));
hierDataSource.then(function(dataSource) {
viewer.dataSources.add(dataSourceCollection.add(dataSource));
});
};
getData().done(processData);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
});

``

Second, I would be pleased to know how to bypass AJAX altogether, but don’t see how to pass the URL with the query string. How would the command CzmlDataSource.load(‘hierarchy.php’) change if my query in hierarchy.php is:

“SELECT DISTINCT unitId,dateTimeStart,counter FROM output_SUBUNITS”

``

Thanks again, erik