Openlayers - LayerRedraw() / Feature rotation / Linestring coords - javascript

TLDR: I have an Openlayers map with a layer called 'track' I want to remove track and add track back in. Or figure out how to plot a triangle based off one set of coords & a heading(see below).
I have an image 'imageFeature' on a layer that rotates on load to the direction being set. I want it to update this rotation that is set in 'styleMap' on a layer called 'tracking'.
I set the var 'stylemap' to apply the external image & rotation.
The 'imageFeature' is added to the layer at the coords specified.
'imageFeature' is removed.
'imageFeature' is added again in its new location. Rotation is not applied..
As the 'styleMap' applies to the layer I think that I have to remove the layer and add it again rather than just the 'imageFeature'
Layer:
var tracking = new OpenLayers.Layer.GML("Tracking", "coordinates.json", {
format: OpenLayers.Format.GeoJSON,
styleMap: styleMap
});
styleMap:
var styleMap = new OpenLayers.StyleMap({
fillOpacity: 1,
pointRadius: 10,
rotation: heading,
});
Now wrapped in a timed function the imageFeature:
map.layers[3].addFeatures(new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(longitude, latitude), {
rotation: heading,
type: parseInt(Math.random() * 3)
}
));
Type refers to a lookup of 1 of 3 images.:
styleMap.addUniqueValueRules("default", "type", lookup);
var lookup = {
0: {
externalGraphic: "Image1.png",
rotation: heading
},
1: {
externalGraphic: "Image2.png",
rotation: heading
},
2: {
externalGraphic: "Image3.png",
rotation: heading
}
}
I have tried the 'redraw()' function: but it returns "tracking is undefined" or "map.layers[2]" is undefined.
tracking.redraw(true);
map.layers[2].redraw(true);
Heading is a variable: from a JSON feed.
var heading = 13.542;
But so far can't get anything to work it will only rotate the image onload. The image will move in coordinates as it should though.
So what am I doing wrong with the redraw function or how can I get this image to rotate live?
Thanks in advance
-Ozaki
Add: I managed to get
map.layers[2].redraw(true);
to sucessfully redraw layer 2. But it still does not update the rotation. I am thinking because the stylemap is updating. But it runs through the style map every n sec, but no updates to rotation and the variable for heading is updating correctly if i put a watch on it in firebug.
If I were to draw a triangle with an array of points & linestring.
How would I go about facing the triangle towards the heading.
I have the Lon/lat of one point and the heading.
var points = new Array(
new OpenLayers.Geometry.Point(lon1, lat1),
new OpenLayers.Geometry.Point(lon2, lat2),
new OpenLayers.Geometry.Point(lon3, lat3)
);
var line = new OpenLayers.Geometry.LineString(points);
Looking for any way to solve this problem Image or Line anyone know how to do either added a 100rep bounty I am really stuck with this.
//From getJSON request//
var heading = data.RawHeading;
Adding and removing the imageFeature

Solved the problem as follows:
var styleMap = new OpenLayers.StyleMap({
fillOpacity: 1,
pointRadius: 10,
rotation: "${angle}",
});
var lookup = {
0: { externalGraphic: "Image1.png", rotation: "${angle}" },
1: { externalGraphic: "Image2.png", rotation: "${angle}" },
2: { externalGraphic: "Image3.png", rotation: "${angle}" }
}
styleMap.addUniqueValueRules("default", "type", lookup);
map.layers[3].addFeatures(new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(lon, lat), {"angle": dir, type: parseInt(Math.random() * 3)}
), {"angle": dir});
then the request:
var dir = (function () {
$.ajax({
'async': false,
'global': true,
'url': urldefault,
'dataType': "json",
'success': function (data) {
dir = data.Heading
}
});
return dir;
})();
Problem solved. Works perfectly.

You can also try to put heading on the object as an attribute:
{"mapFeatures": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "1579001",
"x": 51.0,
"y": 1.2,
"geometry": {
"type": "Point",
"coordinates": [
51.0,
1.2
],
"crs": {
"type": "OGC",
"properties": {
"urn": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
}
},
"properties": {
"heading": 45,
"label": "some_label_goes_here"
}
}
]
}
}
Then you would have to rewrite your lookup function like this:
var lookup = {
0: {externalGraphic: "Image1.png", rotation: ${heading}},
1: {externalGraphic: "Image2.png", rotation: ${heading}},
2: {externalGraphic: "Image3.png", rotation: ${heading}}
}
Could you try that and see if it works? If you don' t know if the attributes are set correctly, you can always debug with firebug, that is what I always do. There is one tricky thing; when parsing geojson; "properties" are translated to "attributes" on the final javascript object.

First guess:
I assume your layer has a single point object that moves and rotates as when following a car with GPS?
It might be better if you would simply destroy all features on the layer (assuming it is only one feature) and redraw the feature with the new heading set.
Second guess:
Perhaps you need to use a function instead of a variable to maintain the live connection to the rotation.
Please check the documentation here: http://trac.openlayers.org/wiki/Styles on styles.
Hope this helps a bit.

Related

Hide leaflet features out of specified area

I'm trying to hide some leaflet features outside of a defined area.
I have a leaflet map displaying rivers as features on a RiverLayer and a circleLayer used to draw an area around the current center of the map.
Each river is separated in multiple parts inside my database and I retrieve only the parts intersecting with my current circle area.
The result look like this:
The rivers are showing outside the area, because I selected the parts intersecting with it.
I could select in my database all the parts within the area but I would lose the parts that are not entirely inside the area.
Calculating the intersection point for each part concerned in order to adjust the coordinates would be a solution but a complex one.
In fact, I would prefer to simply hide these overflows on the client side but I can't find a solution.
Is there a possibility with leaflet to do something like this?
Thanks for you time
Here is an example using turfJS using the booleanWithin and lineSplit functions.
I did the example on a simple basic HTML and Vanilla JS. I added another linestring on the "river" to simulate an outside the circle river
var mymap = L.map('mapid').setView([43.63458105967136, 1.1613321304321291], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 20,
attribution: 'Map data © OpenStreetMap contributors',
}).addTo(mymap);
var center = [43.63458105967136, 1.1613321304321291];
var radius = 1500;
// L.circle(center, radius, {
// color: '#ff4081', fillColor: '#ff4081', fillOpacity: 0.5
// }).addTo(mymap);
var riverGeoJSON = [
{ "type": "Feature", "geometry": { "coordinates": [[1.159444487444759, 43.633815447205706], [1.160243520516838, 43.634633600388156], [1.160731009187281, 43.6350432633719], [1.161774921971743, 43.63541373375439], [1.162079879908259, 43.63564209781788], [1.162320030539753, 43.635959368371424], [1.162373764624914, 43.636409391647234], [1.161800286153361, 43.637212422659154], [1.160910734693605, 43.63832601539633], [1.160651867030764, 43.63886255455486], [1.160332394101095, 43.639317964879666], [1.159189872203288, 43.640743176542664], [1.158053840843969, 43.641810274789506], [1.156922548158863, 43.642651534145514], [1.155851918485514, 43.64349381183714], [1.155156982509935, 43.644214650781954], [1.15326441791592, 43.64594659208024], [1.152374775964331, 43.6470151231795], [1.151428904349222, 43.64790448439313], [1.151107886218696, 43.64840394819371]], "type": "LineString" } },
{ "type": "Feature", "geometry": { "coordinates": [[1.156570800342349, 43.632121495293006], [1.158291185472127, 43.63272397754135], [1.158901458643683, 43.633090727638866], [1.159444487444759, 43.633815447205706]], "type": "LineString" } },
{ "type": "Feature", "geometry": { "coordinates": [[1.168152938761366, 43.62917262321181], [1.167467920251437, 43.62939958202886], [1.166101976396903, 43.62960874939632], [1.164673843635074, 43.629863651007135], [1.163738326615552, 43.63021236020524], [1.163236303364402, 43.630566588076604], [1.162728104605807, 43.63119071739829], [1.161282685092185, 43.632253508072225], [1.160336935333006, 43.633151033736986], [1.159444487444759, 43.633815447205706]], "type": "LineString" } },
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
1.0526275634765625,
43.550289946081115
],
[
1.07940673828125,
43.63334186269
],
[
1.0764884948730469,
43.6336524704596
]
]
}
}
];
// L.geoJSON(riverGeoJSON, {}).addTo(mymap);
var centerGeoJSON = [center[1], center[0]];
var radiusGeoJSON = radius / 1000;
var options = { steps: 50, units: 'kilometers' };
var circleGeoJSON = turf.circle(centerGeoJSON, radiusGeoJSON, options);
L.geoJSON(circleGeoJSON, {}).addTo(mymap);
var riverClipped = {}
for (let index = 0; index < riverGeoJSON.length; index++) {
const feature = riverGeoJSON[index];
var within = turf.booleanWithin(feature, circleGeoJSON);
console.log({ within });
var split = turf.lineSplit(feature, circleGeoJSON);
console.log({ split });
if (within && split.features.length === 0) {
L.geoJSON(feature, {}).addTo(mymap);
} else {
L.geoJSON(split.features[0], {}).addTo(mymap);
}
}
Circle is calculated with turfJS to have a valid GeoJSON feature. This feature is then used as a splitter.
When line is completely inside the circle, the within function returns true, the split function doesn't return a split feature.
When line is completely outside the circle, the within function is false and the split function doesn't return a split feature.
When the line intersect the circle, the within function returns false, and the first feature from the split feature collection is the one inside the circle.
Complete source code on JSFiddle: https://jsfiddle.net/tsamaya/6sc58m7u/

How to collide with custom sprite bounds in Phaser

I have a file pickle.png with a custom hitbox in a pickle.json file like this which I created using PhysicsEditor.
{
"pickle": [
{
"density": 2, "friction": 0, "bounce": 0,
"filter": { "categoryBits": 1, "maskBits": 65535 },
"shape": [ 468, 156 , 399, 214 , 365, 222 , 387, 98 , 414, 100 , 443, 113 , 467, 131 ]
} ,
// etc
]
}
In my preload function I put this:
this.game.load.physics("pickle_physics", "pickle.json");
and in the create function:
game.physics.startSystem(Phaser.Physics.P2JS);
this.pickle = game.add.sprite(400, 300, '/pickle.png');
game.physics.p2.enable(this.pickle, true);
this.pickle.body.loadPolygon('pickle_physics', 'pickle');
// this is a separate sprite with default bounds
this.foo = mt.create('foo1');
game.physics.p2.enable(this.foo, true);
if I inspect foo and pickle in the browser console they are both the same kind of sprite object.
Now I want to make them collide, so I add this to the update function:
this.game.physics.arcade.collide(
this.foo, this.pickle, function(foo, pickle) {
}, null, this
)
The net result of all of this is what you can see in the following gif (note, cylindrical object is a kool-aid soaked pickle):
They are not colliding at all, and the pickle looks terrible. I don't want to see the rectangle around it, or the vertices.
I see there's an example here but I'm having trouble making sense of it.
edit great news, I've made a bit of progress with the help of the collision-groups example.
// collision setup for non-rectanular sprites
game.physics.p2.setImpactEvents(true);
game.physics.p2.restitution = 0.8;
foo.body = new Phaser.Physics.P2.Body(game, foo, 0, 0)
var foo_collision = game.physics.p2.createCollisionGroup();
var pickle_collision = game.physics.p2.createCollisionGroup();
game.physics.p2.updateBoundsCollisionGroup();
this.foo.body.setCollisionGroup(foo_collision);
this.foo.body.collides([foo_collision, pickle_collision]);
this.pickle.body.setCollisionGroup(pickle_collision);
this.pickle.body.collides(foo_collision, function(pickle, foo) {
console.log('hit')
}, this);
At first I had an error with this because foo.body didn't respond to setCollisionGroup. foo.body was constructed using Arcade physics, so I needed to replace it with a Phaser.Physics.P2.Body instance. The result of this is I have collisions, but not in the custom bounds:
I had to change the following lines
game.physics.p2.enable(this.pickle, true);
game.physics.p2.enable(this.foo, true);
and make it false instead of true . The true means it's debug mode, and will show all those ugly borders and vertices. This is covered in the following tutorial, which was very useful in all this: https://www.codeandweb.com/physicseditor/tutorials/phaser-p2-physics-example-tutorial.
Second, before this.pickle.body.loadPolygon('pickle_physics', 'pickle'); I needed to add this.pickle.body.clearShapes(); to remove the outer rectangle bounds.
The result is this:

Polyline geometry to graphic - SimpleLineSymbol is the only type not displaying on the map

I have modified the ESRI ArcGIS js API Measurement widget to keep a session based history of the measurements the user has made. When a user clicks on a history item, it should display the geometry associated with that history item as a GraphicsLayer on the map. I am using knockout to manage the history items and to retrieve measurement metadata when a history item is clicked.
At this point, both my Polygons (for area) and Points (for location) work just fine with the SimpleFillSymbol() and the SimpleMarkerSymbol(), respectively. However, the Polyline geometry returned from a distance measurement is not displaying on the map with the SimpleLineSymbol().
Here's the code:
var graphicLayerId = "measurementHistoryGraphicsLayer";
function addGraphicsLayerToMap(graphicsLayer) {
var lay = getGraphicsLayerFromMap();
if (lay !== undefined) {
lay.clear();
lay.add(graphicsLayer);
map.removeLayer(lay);
}
map.addLayer(graphicsLayer);
}
function createGraphicFromGeometry(viewModel) {
//Determine the symbol type
var symbol;
switch (viewModel.activeTool) {
case "area":
symbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID,
new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new esri.Color([255, 0, 0]), 2),
new esri.Color([255, 0, 0, 0.25]));
break;
case "distance":
symbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new esri.Color([255, 0, 0]), 3);
break;
case "location":
symbol = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_SQUARE, 10,
new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new esri.Color([255, 0, 0]), 3),
new esri.Color([0, 255, 0, 0.25]));
break;
}
var graphic = new esri.Graphic(viewModel.geometry, symbol, { "extent": viewModel.extent, "unitName": viewModel.unitName });
return graphic;
}
function createGraphicsLayerFromGraphic(graphic) {
var graphicLayer = new esri.layers.GraphicsLayer({ id: graphicLayerId });
graphicLayer.add(graphic);
graphicLayer.setRenderer(new esri.renderer.SimpleRenderer(graphic.symbol));
return graphicLayer;
}
function getGraphicsLayerFromMap() {
return map.getLayer(graphicLayerId);
}
$(document).on('click', '#emv_measurement_history .list-group-item', function () {
$('#emv_measurement_history .list-group-item.list-group-item-info').removeClass('list-group-item-info');
$(this).addClass('list-group-item-info');
var measurementData = ko.mapping.toJS(ko.dataFor($(this)[0]));
var graphic = createGraphicFromGeometry(measurementData);
var graphicsLayer = createGraphicsLayerFromGraphic(graphic);
addGraphicsLayerToMap(graphicsLayer);
map.setExtent(measurementData.extent);
});
Like I said, this works fine for both area and location, but distance does not seem to work. I've even tried adding a hard-coded polyline value in there are creating a SimpleLineSymbol from that without success.
For additional information, here is the Polyline info:
[
[
[
2591769.2297164765,
5236836.417134136
],
[
2573584.2281166334,
4620357.96034264
],
[
2557384.1428811993,
4038303.8136230526
],
[
3124973.8484519687,
4260007.60486125
],
[
3714518.451309448,
4454862.77067183
],
[
4324318.833989203,
4618552.510359674
],
[
4666465.839330839,
4693607.843734423
],
[
5013294.285789721,
4757423.375729576
]
]
]
And the spatial reference is set to 102100.
I finally figured it out.
I have the geometry from the original measurement stored in a knockout variable. When I was reading from it, it would build out the graphic, symbol, and graphic layer just fine without any errors throwing.
I discovered that for some reason, the data and the spatial reference were mismatched, so I extracted the path from the stored geometry, assigned it to a new polyline variable, re-set the spatial reference to 102100 like I needed, and re-assigned the geometry to the graphic, which worked.
var g = new esri.Graphic(viewModel.geometry, symbol, { "extent": viewModel.extent, "unitName": viewModel.unitName });
if (viewModel.activeTool === "distance") {
var polyline = new esri.geometry.Polyline(viewModel.geometry.paths);
polyline.setSpatialReference(new esri.SpatialReference(102100));
g.setGeometry(polyline);
}

update choropleth by string (not by fillKey prop)

I read the guide->updating after initial drawing part at https://github.com/markmarkoh/datamaps but updating doesn't work using string values (it works fine using fillKey property instead). I read this closed issue too: markmarkoh/datamaps#118 but nothing.
This is my code:
v
ar map = new Datamap({
element: document.getElementById('world'),
geographyConfig: {
dataUrl: 'world-topo-min.json',
borderColor: 'black'
},
scope: 'countries',
fills: {
defaultFill: 'rgb(255,255,255)',
someKey: '#08306b'
},
data: {
'108': {fillKey: 'someKey'}
},
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([30, 34.4444])
.scale(170)
.translate([element.offsetWidth / 2 , element.offsetHeight/2]);
var path = d3.geo.path().projection(projection);
return {path: path, projection: projection};
}
});map.updateChoropleth({'57': {fillKey:'someKey'},'116': '#08306b'});
Country identificated by id=57 is ok, country 116 doesn't change
I pull data from a PHP-array like this:
myarray=[[57,32],[116,12]]
Country 57 has value 32, country 116 has value 12 and so on.
I ignore myarray right now because I want to solve updatechoropleth issue first
Obviously, I'm going to create a linear scale to put right colors into countries path but this is another thing.
Help me please
Thank you guys!

Print FeatureLayer labels in Esri JavaScript API 3.5 and earlier

I have a need to implement labels on features in a FeatureLayer in version 3.5 if Esri's Javascript API. The labels are from a field returned by a REST feature service. I can't move to 3.7 for various reasons at this time. I have tried using a TextSymbol but my map features just turn to the color of the TextSymbol and no text appears. I may be approaching this in he wrong manner, though. Below is the code I'm attempting to use for labeling with the featureLayer object being my instance of the FeatureLayer I'm adding to the map. Is there a different or proper way to accomplish this task?
featureLayer.on("graphic-add", function (evt) {
var labelColor = new Color([255, 0, 0, 0.25]);
var myLabel = new TextSymbol(evt.graphic.attributes["My Field Name"]);
myLabel.setColor(labelColor);
myLabel.font.setSize("14pt");
evt.graphic.setSymbol(myLabel);
//console.log(evt);
});
Thanks for any help that can be provided!
I was able to solve this with the code below. This seems to work great.
var labelList = new Array();
featureLayer.on("update-end", function (evt) {
for (var i = 0; i < evt.target.graphics.length; i++) {
var gfx = evt.target.graphics[i];
//if label hasn't been added go ahead and generate it and add to array
if (labelList.indexOf(gfx.attributes[idField]) == -1) {
labelList.push(gfx.attributes[idField]);
addLabelToGeometry(gfx.attributes[labelField], gfx.geometry);
}
}
});
function addLabelToGeometry(text, geometry) {
var point = geometry.getExtent().getCenter();
//top level label of text
var TextSymbolJson = {
"type": "esriTS",
"color": [0, 0, 0, 255],
"verticalAlignment": "middle",
"horizontalAlignment": "center",
"font": {
"family": "Helvetica",
"size": 12,
"style": "normal",
"weight": "bold",
"decoration": "none"
}
};
var labelTextSymbol = new esri.symbol.TextSymbol(TextSymbolJson);
labelTextSymbol.setText(text);
var labelGraphic = new esri.Graphic(point, labelTextSymbol);
map.graphics.add(labelGraphic);
}

Categories