I scenario is below :
map is shown under from TiledWMS layer from mapserver. It has 2 layers.
TiledWMS layer for OSM world map.
TiledWMS layer for layers defined in kml file placed in mapserver through .map file. This map file contains many layers.
Now , when user click on map : it got 2 layers as above.
But since 2nd layer is made up of different layers as given in .map file , i am not able to uniquely identify these layers. I want that since 2 nd layer is made up of different layers in kml file i should be able to uniquely identify them on mouse click or hower.
Thanks
Satpal
I am able to get it : below is samaple code for others.
var coord = evt.coordinate;
var pixel = $scope.map.getPixelFromCoordinate(coord);
var viewProjection = $scope.map.getView().getProjection();
var viewResolution = $scope.map.getView().getResolution();
var numberOfLayersOnMap = $scope.map.getLayers();
var feature = $scope.map.forEachFeatureAtPixel(pixel, function(feature, layer){return feature;}, null, function(layer) {return true;});
if(feature === undefined)
{
$scope.map.forEachLayerAtPixel(pixel, function (layer)
{
if(!layer)
{
return ;
}
var urlWMSGetFeatureInfo = layer.getSource().getGetFeatureInfoUrl(coord, viewResolution, viewProjection, {
'INFO_FORMAT': 'application/vnd.ogc.gml'
});
if(urlWMSGetFeatureInfo.indexOf("osm-google.map")<0)
{
$http({
method: 'GET',
url: urlWMSGetFeatureInfo,
}).success(function(data){
var parser = new ol.format.WMSGetFeatureInfo();
var features = parser.readFeatures(data);
if(features.length>0)
{
var featureName = features[0].n.Name;
topOverlayElement.innerHTML = featureName;
$scope.highlightOverlay.setFeatures(new ol.Collection());
if($scope.flagLinkage == true)
{
var xmlObj = utility.StringToXML(data);
var xmlDocumnet = xmlObj.childNodes[0];
var layerNode = xmlDocumnet.children[0];
var gmlLayerNode = layerNode.children[0];
var layerName = gmlLayerNode.textContent;
var layerInfoObject = {};
layerInfoObject.layerName = layerName;
//layerInfoObject.placemarkName = featureName;
$scope.placemarksSelectedObject.push(layerInfoObject);
$scope.placemarksSelectedFeatureObject.push(features[0]);
}
else
{
$scope.placemarksSelectedFeatureObject.length = 0;
$scope.placemarksSelectedFeatureObject.push(features[0]);
}
$scope.highlightOverlay.setFeatures(new ol.Collection($scope.placemarksSelectedFeatureObject));
var featureDescription = features[0].n.description;
middleOverlayElement.innerHTML = (featureDescription === undefined) ? '' : featureDescription;
$scope.showOverlay(coord);
}
}).error(function (data) {
console.log("Not able to get capabilty data.");
});
}
else
{
$scope.closeOverlay(evt);
}
});
Related
I would like to replace some text box text in Google slides with corresponding images. I have tried to following method: How to replace Text with Image on Google Slide using Google Script
It only works on small amounts of data, but I have over 500 object to loop through. I cannot use the Slides API only apps script.
Are there any efficient ways to go about it?
Here is my code so far:
function addFruits() {
//adding search texts
var apple = "Apple";
var orange = "Orange";
var cherry = "Cherry";
var bamboo = "Bamboo";
//addding file ids
var appleID = 'XXXXXXX';
var orangeID = 'XXXXXXXXXXX';
var cherryID = 'XXXXXXXXX';
var bambooID = 'XXXXXXXXXX';
//getting images
var appleIMG = DriveApp.getFileById(appleID).getBlob();
var orangeIMG = DriveApp.getFileById(orangeID).getBlob();
var cherryIMG = DriveApp.getFileById(cherryID).getBlob();
var bambooIMG = DriveApp.getFileById(bambooID).getBlob();
//Logger.log(appleIMG)
//Logger.log(orangeIMG)
//Logger.log(cherryIMG)
//Logger.log(bambooIMG)
// retreive all slides.
var presentation = SlidesApp.openById(slideID);
var slides = presentation.getSlides();
//Logger.log(slides)
//get all shapes and reduce them to a 1d array
var shapesArrays = [];
slides.forEach(slide => {
let shape = slide.getShapes();
shapesArrays.push(shape)
})
var shapes = [].concat.apply([], shapesArrays);
//Logger.log(shapes)
shapes.forEach(s => {
if (s.getText().asString().includes(apple)) {
s.replaceWithImage(appleIMG);
}
else if (s.getText().asString().includes(orange)) {
s.replaceWithImage(orangeIMG);
}
else if (s.getText().asString().includes(cherry)) {
s.replaceWithImage(cherryIMG);
}
else if (s.getText().asString().includes(bamboo)) {
s.replaceWithImage(bambooIMG);
}
});
}
Try this:
function addFruits() {
const ids = [{ id: "id1", name: "name1",{ id: "id2", name: "name2" }];
var presentation = SlidesApp.openById(slideID);
var slides = presentation.getSlides();
slides.forEach(slide => {
let shapes = slide.getShapes();
shapes.forEach(shape => {
let text = shape.getText().asString();
ids.forEach(e => {
if (text.includes(id.name)) {
shape.replaceWithImage(DriveApp.getFileById(e.id).getBlob());
}
});
});
});
}
You can limit the number of slides you attempt by limiting the size of ids
I have an Excel file with the following content:
Inside my component.ts, I extract the Excel's content as follow:
var testUrl= "excel.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", testUrl, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i){
arr[i] = String.fromCharCode(data[i]);
}
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {type:"binary"});
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
var json = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {header:1, raw:true});
var jsonOut = JSON.stringify(json);
console.log("test"+jsonOut);
}
oReq.onerror = function(e) {
console.log(e);
}
oReq.send();
XLSX.utils.sheet_to_json will format JSON as follow:
However, I would like the JSON to be as follow:
Most probably I would need to manually create the JSON, but can anyone help me point to the direction on how I can accomplish this?
In your case we need to modify the JSON data by looping over XLSX.utils.sheet_to_json JSON object:
// This object will contain the data in the format we want
var finalObj = { "object": []};
// Variables to track where to insert the data
var locIndex, firstCondIndex, secondCondIndex,
lockey, firstCondKey, secondCondkey;
// We need to initialize all indexes to -1 so that on first time we can get 0, as arrays start with 0 in javascript
locIndex = -1;
// here obj is XLSX.utils.sheet_to_json
obj.object.map((value, index) => {
// we don't want to consider name of columns which is first element of array
if(!index) return;
// Go inside only if not null
if(value[0]) {
// For Location
finalObj.object.push(createObj(value[0]));
locIndex++;
// We also need to store key names to push it's children
lockey = value[0];
firstCondIndex = -1;
}
if(value[1]) {
// For First Condition
finalObj.object[locIndex][lockey].push(createObj(value[1]));
firstCondIndex++;
firstCondKey = value[1];
secondCondIndex = -1;
}
if(value[2]) {
// For Second Condition
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey].push(createObj(value[2]));
secondCondIndex++;
secondCondkey = value[2];
}
if(value[3]) {
// For Products
// We just push the string
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey][secondCondIndex][secondCondkey].push(value[3]);
}
});
function createObj(val) {
// We need to initialize blank array so we can push the children of that element later on
var obj = {};
obj[val] = [];
return obj;
}
console.log(finalObj);
I'm trying to display a heatmap over the globe in Cesium but the globe isn't even showing up on the screen, only the background is. I looked in the network part of google chrome and it shows the actual image I need being loaded from the server.
<script>
var count=0;
var viewer = new Cesium.CesiumWidget('cesiumContainer');
var layers = viewer.scene.imageryLayers;
var imageArray = <?php echo json_encode($images) ?>// PARSING PHP ARRAY INTO JAVASCIPT
alert(imageArray[0]);
var date;var name='HeatMap-2006-01-16.png'; //FOR INITAL PAGE LOAD
loadCesium();
function loadCesium()
{
//Cesium Active Window
layers.addImageryProvider(new Cesium.SingleTileImageryProvider({
url : 'images/'.concat(name),
rectangle : Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0)
}));
}
function overlayChange()
{
name = imageArray[count];
for (i = 0; i < name.length; i++)
{
if(name.charAt(i)=="-")
{
date = name.substring(i);
break;
}
}
loadCesium();
count = count + 1;
}
function overlayChangeBack()
{
if(count == 0)
{
count = 39;
name = 'HeatMap';
name = name.concat(count.toString());
loadCesium();
}
else
{
name = 'HeatMap';
count=count-1;
name = name.concat(count.toString());
loadCesium();
}
}
</script>
Right now I'm just trying to display the name variable('HeatMap-2006-01-16.png') for the initial image but it's not displaying. No image I try to put instead displays either so it's definitely an issue with cesium.
I'm not sure why this fixed it because I've had it working without this statement but when declaring the cesiumContainer in the variable viewer, you have to set it as this:
var viewer = new Cesium.CesiumWidget('cesiumContainer', {
imageryProvider : new Cesium.ArcGisMapServerImageryProvider({
url : 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
}),
baseLayerPicker : false
});
I have an ajax request which helps me to get a JSON-object from a webserver!
function _loadModel(filename) {
var request = new XMLHttpRequest();
request.open("GET", filename);//open(method, url, async)
request.onreadystatechange = function() {
console.info(request.readyState +' - '+request.status);
if (request.readyState == 4) {//4 == finished download
if(request.status == 200) { //OK -> bezogen auf http Spezifikation
handleLoadedGeometry(filename,JSON.parse(request.responseText));
}
else if (document.domain.length == 0 && request.status == 0){ //OK but local, no web server
handleLoadedGeometry(filename,JSON.parse(request.responseText));
}
else{
alert ('There was a problem loading the file :' + filename);
alert ('HTML error code: ' + request.status);
}
}
}
request.send();// send request to the server (used for GET)
}
_loadModel('http://localhost:8080/bbox?XMIN=3500060&YMIN=5392691&XMAX=3500277&YMAX=5393413')
JSON file:
[{"building_nr": 5, "geometry": "{\"type\":\"Polygon\",\"coordinates\":[[[3500267.16,5392933.95,456.904],[3500259.19,5392933.01,456.904],[3500258.586,5392938.152,456.904],[3500258.02,5392942.97,456.904],[3500265.98,5392943.94,456.904],[3500266.552,5392939.097,456.904],[3500267.16,5392933.95,456.904]]]}", "polygon_typ": "BuildingGroundSurface"}, ...]
This is one object and I have a lot of them in this array.
Now I want to create a mesh!
I think this can be done inside the function handleLoadedGeometry()
//Callback funktion
function handleLoadedGeometry(filename, model) {
var geom = new THREE.BufferGeometry();
for (var i=0;i<10;i++)
{
var vertex = new THREE.Vector3();
vertex.x = model.geometry[i].coordinates[0];
vertex.y = model.geometry[i].coordinates[1];
vertex.z = model.geometry[i].coordinates[2];
geometry.vertices.push( vertex );
}
geom.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xff00f0 } );
var mesh = new THREE.Mesh( geom, material );
Scene.scene.add(mesh);
}
At the end I get this error in the browser: Cannot read property '0' of undefined
How can I refer to geometry coordinates inside the JSON?
from what you provided it seems the loaded JSON contains an array of multiple objects that is why you get the error
try something like this
function handleLoadedGeometry(filename, models) {
for (var i=0; i<models.length; i++)
{
var model = models[i];
var coordinates = model.geometry.coordinates;
var positions = [];
for (var j=0; j<coordinates.length; j++){
positions.push(coordinates[j][0]);
positions.push(coordinates[j][1]);
positions.push(coordinates[j][2]);
}
var geometry = new THREE.BufferGeometry();
// buffer attributes contain an array not vectors
var positionAttribute = new THREE.BufferAttribute(new Float32Array(positions),3);
geometry.addAttribute("position", positionAttribute);
var material = new THREE.MeshBasicMaterial( { color: 0xff00f0 } );
var mesh = new THREE.Mesh( geom, material );
Scene.scene.add(mesh);
}
}
or remove the first loop if you call it for each object in the JSON array
I did it in another way...I just created instead of BufferGeometry the default Geometry in three.js:
function handleLoadedGeometry(filename) {
var material = new THREE.MeshBasicMaterial({color: 0xFF0000});
for (var i=0; i<filename.length; i++)
{
var model = filename[i]; // erstes Objekt
var coordinates = JSON.parse(model.geometry);
var geometry = new THREE.Geometry();
var coordinates_updated = _transformCoordinates(coordinates.coordinates[0]);
for (var j = 0; j<coordinates_updated.vertices.length; j++){
geometry.vertices.push(
//new THREE.Vector3(coordinates.coordinates[0][j][0], coordinates.coordinates[0][j][1], coordinates.coordinates[0][j][2])//x,y,z Koordinatenpunkte für Surface 1
new THREE.Vector3(coordinates_updated.vertices[j][0],coordinates_updated.vertices[j][1],coordinates_updated.vertices[j][2])
);
geometry.faces.push(
new THREE.Face3(0,1,2),
new THREE.Face3(0,3,2)
geometry.computeBoundingSphere();
}
var mesh = new THREE.Mesh(geometry, material);
Scene.scene.add(mesh);
}
};
And now it works!
I think BufferGeometry is more for more complex surfaces.
I wanted to move the model dynamically using keyboard shortcuts. I could not find relevant article on that.
So for now, I'm trying to move the model on click. When click on the model. The model has to move in one direction (increment the value 1 on tick). Find below the sandcastle code for that.
var selectedMesh; var i=0;
var viewer = new Cesium.Viewer('cesiumContainer', {
infoBox: false,
selectionIndicator: false
});
var handle = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
function createModel(url, height) {
viewer.entities.removeAll();
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);
var entity = viewer.entities.add({
name: url,
position: position,
orientation: orientation,
model: {
uri: url,
minimumPixelSize: 128
}
});
viewer.trackedEntity = entity;
viewer.clock.onTick.addEventListener(function () {
if (selectedMesh) {
console.log("Before 0 : " + selectedMesh.primitive.modelMatrix[12]);
selectedMesh.primitive.modelMatrix[12] = selectedMesh.primitive.modelMatrix[12] + 1;
console.log("After 0 : " + selectedMesh.primitive.modelMatrix[12]);
}
});
}
handle.setInputAction(function (movement) {
console.log("LEFT CLICK");
var pick = viewer.scene.pick(movement.position);
if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
if (!selectedMesh) {
selectedMesh = pick;
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
var options = [{
text: 'Aircraft',
onselect: function () {
createModel('../../SampleData/models/CesiumAir/Cesium_Air.bgltf', 5000.0);
}
}, {
text: 'Ground vehicle',
onselect: function () {
createModel('../../SampleData/models/CesiumGround/Cesium_Ground.bgltf', 0);
}
}, {
text: 'Milk truck',
onselect: function () {
createModel('../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.bgltf', 0);
}
}, {
text: 'Skinned character',
onselect: function () {
createModel('../../SampleData/models/CesiumMan/Cesium_Man.bgltf', 0);
}
}];
Sandcastle.addToolbarMenu(options);
When I click, the model is moving for the first time. After that, It stays on the same place. I've printed the value in the console. It seems the value is not changing. I'm not sure about the problem here. or I'm implementing the transformation wrongly.
If you keep track of the current lat and lon of the entity, and adjust that lat and lon based on user input, all you need to do is update the orientation of the entity.
var lon = // the updated lon
var lat = // updated lat
var position = Cesium.Cartesian3.fromDegrees(lon, lat, height);
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
// create an orientation based on the new position
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);
Then you just need to update the orientation of the entity.
entity.orientation = orientation;
By changing the value, the models orientation, and therefore position will get updated.