In cesium, how do you dynamically update a label over time? - cesiumjs

I have a label that associated with a billboard/marker in cesium that I want to 'update' over time. I tried using a setTimeout to increment a variable 'count' that I assign as the label to a marker... but it doesn't increment. Is there something special I need to be doing or am missing?

You should be able to update a label just by changing its text property.
entity.label.text = 'new text';
Here's a full example:
var viewer = new Cesium.Viewer('cesiumContainer');
var image = new Image();
var entity;
image.onload = function() {
entity = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
billboard : {
position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
scaleByDistance : new Cesium.NearFarScalar(1.5e2, 5.0, 1.5e7, 0.5),
image : image
},
label : {
text : 'Label on top of scaling billboard',
font : '20px sans-serif',
showBackground : true,
horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
pixelOffset : new Cesium.Cartesian2(0.0, -image.height),
pixelOffsetScaleByDistance : new Cesium.NearFarScalar(1.5e2, 3.0, 1.5e7, 0.5)
}
});
viewer.zoomTo(viewer.entities);
};
image.src = '../images/facility.gif';
var counter = 0;
viewer.scene.postUpdate.addEventListener(function(){
if(!Cesium.defined(entity)) {
return;
}
counter += 0.04;
if(Math.cos(counter) > 0){
entity.label.text = "On";
} else {
entity.label.text = "Off";
}
});
And a live version on Sandcastle.

Related

Line chart not showing in PrimeFaces chart with time in Y-axis

PrimeFaces: 6.0.0
I would like to display line chart. In that chart,
X-Axis should display Sce_1, Sce_2.... etc.,
Y-Axis should display Time in HH:MM:SS format
Currently, I could display values in both x-Axis, but the chart is not displayed.
Chart :
enter image description here
Following is my code:
In Xhtml file:
<p:chart id="gp2" type="line" model="#{student.areaModel}" extender="ext2" style="height:400px;width:800px" />
Java Script:
Note: I have imported jqplot-1.4.20.jar in my project
<script type="text/javascript" src="/org/wicketstuff/jqplot/behavior/plugins/jqplot.dateAxisRenderer.min.js"></script>
<script type="text/javascript">
//<![CDATA[
function ext2() {
//this = chart widget instance
//this.cfg = options
this.cfg.axes = {
xaxis : {
rendererOptions : {
tickRenderer : $.jqplot.CanvasAxisTickRenderer
},
tickOptions : {
fontSize : '10pt',
fontFamily : 'Tahoma',
angle : 30
}
},
yaxis : {
min : null,
max : null,
autoscale : true,
numberTicks : null,
pad : 1.0,
tickInterval : '1 days',
renderer : $.jqplot.DateAxisRenderer,
rendererOptions : {
tickInset : 0
},
tickRenderer : $.jqplot.CanvasAxisTickRenderer,
tickOptions : {
fontSize : '10pt',
fontFamily : 'Tahoma',
angle : -40
}
}
};
this.cfg.highlighter = {
show : true,
tooltipOffset : 2
}
};
//]]>
</script>
In Backingbean file,
public void graph_04()
{
if(areaModel != null)
{
areaModel.clear();
}
areaModel = new LineChartModel();
DateAxis Yaxis = new DateAxis("Time");
Yaxis.setMin("00:00:00");
Yaxis.setMax("00:59:59");
Yaxis.setTickFormat("%H:%#M:%S");
areaModel.getAxes().put(AxisType.Y, Yaxis);
Axis xAxis = new CategoryAxis("Sce Name");
areaModel.getAxes().put(AxisType.X, xAxis);
xAxis.setTickAngle(-30);
areaModel.setStacked(true);
areaModel.setShowPointLabels(true);
LineChartSeries ch = new LineChartSeries();
ch.setLabel("List");
ch.set("Sce_1", new Time(00,10,10).getTime());
ch.set("Sce_2", new Time(00,20,10).getTime());
ch.set("Sce_3", new Time(00,30,12).getTime());
ch.set("Sce_4", new Time(00,40,18).getTime());
ch.set("Sce_5", new Time(00,50,56).getTime());
ch.set("Sce_6", new Time(00,22,30).getTime());
ch.set("Sce_7", new Time(00,18,40).getTime());
areaModel.addSeries(ch);
}
Why chart value is not displaying in chart?

How to show floors to on a polygon using CesiumJs

I am new to CesiumJs and I want to add 12 floors to a building. I have created the building using polygon.
Here is the code I have used to create the polygon
var viewer = new Cesium.Viewer('cesiumContainer');
var wyoming = viewer.entities.add({
name : 'My location',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([cordinates of location]),
material : Cesium.Color.WHITE.withAlpha(0.5),
outline : true,
fill : true,
outlineColor : Cesium.Color.BLACK,
}
});
wyoming.polygon.extrudedHeight = 50;
viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(-79.38443,43.64843, 144.00),
orientation : {
heading : Cesium.Math.toRadians(121.00),
pitch : Cesium.Math.toRadians(60.00 - 90.0),
roll : 0.0
},
duration : 4.0, // in seconds
complete : function() {
},
point : {
pixelSize : 5,
color : Cesium.Color.RED,
outlineColor : Cesium.Color.WHITE,
outlineWidth : 2
},
label : {
text : 'My another location',
font : '14pt monospace',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
pixelOffset : new Cesium.Cartesian2(0, -9)
}
});
Thanks in advance
In this case you will need something more complex than extruded polygon.
If you need a simple building with floors of alternating color you can construct it from Wall entity with stripe material and putting a polygon on top of it as a "roof" (use same coordinates, put height property to the height of the wall, and not set extrudedHeight).
This will create wall with alternating black and white floors:
function createBuildingWalls(coordinates, floors)
{
var floorHeight = 4;
var height = floors * floorHeight;
var low = Array.apply(null, Array(coordinates.length/2)).map(function() { return 0 });
var high = Array.apply(null, Array(coordinates.length/2)).map(function() { return height });
var buildingWalls = new Cesium.Entity({
name : 'Wall',
wall : {
positions : Cesium.Cartesian3.fromDegreesArray(coordinates),
maximumHeights : high,
minimumHeights : low,
material : new Cesium.StripeMaterialProperty({
evenColor : Cesium.Color.WHITE,
oddColor : Cesium.Color.BLACK,
repeat : 20
})
}});
return buildingWalls;
}
And this roof (might run into an issue with very large polygons, but should be fine for buildings):
function createBuildingRoof(coordinates, floors)
{
var floorHeight = 4;
var buildingHeight = floors * floorHeight;
var buildingRoof = new Cesium.Entity({
name : 'My location',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray(coordinates),
material : Cesium.Color.RED.withAlpha(0.9),
outline : true,
height : buildingHeight,
fill : true,
outlineColor : Cesium.Color.BLACK,
}
});
return buildingRoof;
}
You can also use a texture (image) as a material and apply it to the wall, but it is more complex. You would need to set ImageMaterial property and according propably set repeat property depending on the type of your texture (ie repeat a single floor verticaly, or single 12 floor stripe horizontaly or some other combination)
http://cesiumjs.org/Cesium/Build/Documentation/ImageMaterialProperty.html
Other solution would be to use 3D models of the buildings:
http://cesiumjs.org/2014/03/03/Cesium-3D-Models-Tutorial/

How to move 3D model on Cesium

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.

SQL Titanium using SQLite

I have a database look like this
I'm trying to get the NamaHalaman by doing some sql Query
function getPageByMdl(modul) {
var sql = "SELECT * FROM Halaman WHERE ModulLayanan = '"+modul+"' ORDER BY Urutan ASC";
var results = [];
var sqlResultSet = db.execute(sql);
while (sqlResultSet.isValidRow()) {
results.push({
namahalaman : sqlResultSet.fieldByName('NamaHalaman')
});
sqlResultSet.next();
}
sqlResultSet.close();
return results;
}
However the result length always give me 0 although as you can see it has 2 value in it. Another problem also happen when i try to run
var sql = "SELECT Distinct ModulLayanan FROM Halaman Order ASC";
it only returned the first value from the database which is Whistleblowing system.
Oh here's my function on showing the result
function loadDetailModule() {
data = getPageByMdl(modulTemp);
if (data.length > 0) {
var tableData = [];
//get through each item
for (var i = 0; i < data.length; i++) {
var detailmodul = data[i];
//create table row
var row = Titanium.UI.createTableViewRow({
dataIndex : i,
_title : detailmodul.namahalaman,
hasChild : true,
className : 'detailmodul_halaman',
filter : detailmodul.namahalaman,
height : 70,
backgroundColor : '#fff',
});
//title label for row at index i
var titleLabel = Titanium.UI.createLabel({
text : detailmodul.namahalaman,
font : {
fontSize : 14,
fontWeight : ' bold'
},
left : 70,
top : 10,
height : 50,
width : 210,
color : '#232',
dataIndex : i
});
row.add(titleLabel);
//add our little icon to the left of the row
var iconImage = Titanium.UI.createImageView({
image : 'img/eggcooking.png',
width : 50,
height : 50,
left : 10,
top : 10
});
row.add(iconImage);
//add the row to data array
tableData.push(row);
}
// set the data to tableview's data
detailModuleTable.data = tableData;
detailModuleTable.show();
} else {
detailModuleTable.hide();
}
}
Thank you in advance
the problem is because the Titanium does not refresh your Database when you run your application.
What you need is:
1. uninstall your application in emulator
or
2. you can change the database name
Titanium.Database.install('SLTemp.sqlite', 'SLTemp1');
var db = Ti.Database.open('SLTemp1');
to
Titanium.Database.install('SLTemp.sqlite', 'SLTemp');
var db = Ti.Database.open('SLTemp');

markerclusterer: anchor offset for cluster icons

I'm trying to slightly offset cluster icons created by the Google Maps Markerclusterer (V3). Short of modifying the existing code, I can't find a way to do this. Does anybody have an idea?
The Styles object in which you can provide a custom image URL accepts an anchor property, but this is to offset the generated marker item count.
Thanks!
The proper way to do it is to adjust the anchorIcon property like this:
var clusterStyles = [
{
height: 64,
width: 53,
anchorIcon: [20, 140]
},
{
height: 64,
width: 53,
anchorIcon: [20, 140]
},
{
height: 64,
width: 53,
anchorIcon: [20, 140]
}
];
var mcOptions = {
styles: clusterStyles
};
var markerCluster = new MarkerClusterer(map, markers, mcOptions);
The accepted answer does not work well enough for me - adding transparent space to the icon image can change the way click and hover events behave due to the increased size of the object.
I would use the anchorIcon property except it's only available in Marker Clusterer Plus, not the other Marker Clusterer plugin (which I'm using).
For those that specifically want to use Marker Clusterer - you can override ClusterIcon.prototype.getPosFromLatLng_. The ClusterIcon object is global, so we can modify it at the top-level of any script file without messing with the plugin's source code.
This will anchor the marker to the bottom of the icon:
ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) {
var pos = this.getProjection().fromLatLngToDivPixel(latlng);
pos.x -= parseInt(this.width_ / 2);
pos.y -= parseInt(this.height_);
return pos;
};
I changed the code of marcerclusterer.js to support anchorText parameter by modifying following two functions:
/**
* Sets the icon to the the styles.
*/
ClusterIcon.prototype.useStyle = function() {
var index = Math.max(0, this.sums_.index - 1);
index = Math.min(this.styles_.length - 1, index);
var style = this.styles_[index];
this.url_ = style['url'];
this.height_ = style['height'];
this.width_ = style['width'];
this.textColor_ = style['textColor'];
this.anchor_ = style['anchor'];
this.anchorText_ = style['anchorText']; //added to support anchorText parameter by Frane Poljak, Locastic
this.textSize_ = style['textSize'];
this.backgroundPosition_ = style['backgroundPosition'];
};
/**
* Adding the cluster icon to the dom.
* #ignore
*/
ClusterIcon.prototype.onAdd = function() {
this.div_ = document.createElement('DIV');
if (this.visible_) {
var pos = this.getPosFromLatLng_(this.center_);
this.div_.style.cssText = this.createCss(pos);
////added to support anchorText parameter by Frane Poljak, Locastic
if (typeof this.anchorText_ === 'object' && typeof this.anchorText_[0] === 'number' && typeof this.anchorText_[1] === 'number') {
this.div_.innerHTML = '<span style="position:relative;top:' + String(this.anchorText_[0]) + 'px;left:' + String(this.anchorText_[1]) + 'px;">' + this.sums_.text + '</span>'
} else this.div_.innerHTML = this.sums_.text;
}
var panes = this.getPanes();
panes.overlayMouseTarget.appendChild(this.div_);
var that = this;
google.maps.event.addDomListener(this.div_, 'click', function() {
that.triggerClusterClick();
});
};
You could add some transparent space to one side of your cluster icon's PNG, so that the part of the icon which you'd like to be centred is actually also centred in your PNG. This should not increase the weight of your image by more than a few bytes.
anchor / anchorIcon/ anchorText properties didn't work for me...so I made kind of workaround:
I use setCalculator() function to set the cluster text:
https://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/docs/reference.html
when I am setting the cluster text property I am wrapping the value with <span>,
something like this:
markerCluster.setCalculator(function (markers) {
return {
text: '<span class="myClass">' + value+ '</span>',
index: index
};
});
now you can control the cluster label position with ".myClass":
span.myClass{
position: relative;
top: -15px;
.....
}