I have an issue that is driving me crazy. I have an openlayers map project that works fine. I took this concept code and moved it to a project that utilizes .Net and the projection for the markers/icons get messed up.
//set the Icon/Marker that will be used
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.8,
src: '<%=PinMarkerImage%>'
}))
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: iconStyle
});
//we will zoom the map to fit the locations after we create
//the map
var mapObj = new ol.Map({
layers: [new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer],
target: document.getElementById('map-canvas'),
view: new ol.View({
center: ol.proj.fromLonLat([0, 0]),
zoom: 12
})
});
alert(vectorSource.getExtent());
mapObj.getView().fit(vectorSource.getExtent(), { padding: [75, 40, 40, 75], constrainResolution: false });
//I pass in an object one at a time to populate the features
function changeMapOption(oBranch, i) {
// alert('selected');
var long = oBranch.Longitude;
var lat = oBranch.Latitude;
alert(long + ' ' + lat);
//lastCord = ol.proj.transform([coord[0], coord[1]], 'EPSG:4326', 'EPSG:3857');
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857')), //ol.proj.fromLonLat([long, lat])),
id: oBranch.Id,
title: oBranch.Name,
address: oBranch.Address + ", " + oBranch.City + ", " + oBranch.State + " " + oBranch.ZipCode
});
//alert(iconFeature.getGeometry());
vectorSource.addFeature(iconFeature);
//mapObj.getView().fit(vectorSource.getExtent(), { padding: [75, 40, 40, 75], constrainResolution: false });
//target = mapObj.getTarget();
//This will zoom the map to fit all of the vector Sources in vectorSource
//alert(vectorSource.getExtent());
//mapObj.addOverlay(popup);
//jTarget = typeof target === "string" ? $("#" + target) : $(target);
//element = document.getElementById('popup');
}
I have the alerts set to check the Longitude and Latitude. These are correct. For this test run I have three objects that are populated, the Longitude and Latitudes are as follows:
-112.04883, 40.492104
-95.673328, 29.95752
-95.638558, 29.880014
When I run the code the alert for the vectorSource.getExtent() produces this:
-12473218.699582075,-8426499.834030088,-10646435.576762961,-6361484.120029401
And the markers show up off the lower coast of Chile. The Latitude is wrong, yet the Longitude appears to be correct.
I could certainly use some guidance here. This is driving me crazy.
Thanks for any assistance.
After trying multiple times, I came up with a solution that works. Hopefully this will help someone down the line.
function loadMarker(oBranch, i) {
var sHTML = getMarkerInfoHtml(oBranch);
var long = oBranch.Longitude * 1;
var lat = oBranch.Latitude * 1;
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat(([long, lat]))),
index: oBranch.Id,
id: oBranch.Id,
title: oBranch.Name,
address: sHTML //oBranch.Address + ", " + oBranch.City + ", " + oBranch.State + " " + oBranch.ZipCode
});
vectorSource.addFeature(iconFeature);
}
The key was these two lines:
var long = oBranch.Longitude * 1;
var lat = oBranch.Latitude * 1;
by adding the * 1 to the line it forces JavaScript to treat the variables properly as numeric. It now places the markers in the correct location.
Related
I am trying to run the following code to extract the change map using the Land Trendr algorithm in Google Earth Engine. Everything seems to be running fine when I use a point as my area of interest, but once I try to use a polygon as my aoi file it throws me an error. I am attaching my code here :
//##########################################################################################
// START INPUTS
//##########################################################################################
// define collection parameters
var startYear = 1985;
var endYear = 2017;
var startDay = '06-20';
var endDay = '09-20';
//var aoi = ee.Geometry.Point(-122.8848, 43.7929);
var coords = ([70.9361058400289,28.387332974875402],
[83.5044652150289,28.387332974875402],
[83.5044652150289,37.305336609850876],
[70.9361058400289,37.305336609850876],
[70.9361058400289,28.387332974875402]);
var aoi = ee.Geometry.Polygon(coords);
var index = 'NBR';
var maskThese = ['cloud', 'shadow', 'snow', 'water'];
// define landtrendr parameters
var runParams = {
maxSegments: 6,
spikeThreshold: 0.9,
vertexCountOvershoot: 3,
preventOneYearRecovery: true,
recoveryThreshold: 0.25,
pvalThreshold: 0.05,
bestModelProportion: 0.75,
minObservationsNeeded: 6
};
// define change parameters
var changeParams = {
delta: 'loss',
sort: 'greatest',
year: {checked:false, start:2000, end:2010},
mag: {checked:true, value:200, operator: '\>', dsnr:false},
dur: {checked:true, value:4, operator: '\<'},
preval: {checked:true, value:300, operator: '\>'},
mmu: {checked:true, value:11},
};
//##########################################################################################
// END INPUTS
//##########################################################################################
// load the LandTrendr.js module
var ltgee = require('users/emaprlab/public:Modules/LandTrendr.js');
// add index to changeParams object
changeParams.index = index;
// run landtrendr
var lt = ltgee.runLT(startYear, endYear, startDay, endDay, aoi, index, [], runParams, maskThese);
// get the change map layers
var changeImg = ltgee.getChangeMap(lt, changeParams);
// set visualization dictionaries
var palette = ['#9400D3', '#4B0082', '#0000FF', '#00FF00', '#FFFF00', '#FF7F00', '#FF0000'];
var yodVizParms = {
min: startYear,
max: endYear,
palette: palette
};
var magVizParms = {
min: 200,
max: 800,
palette: palette
};
// display the change attribute map - note that there are other layers - print changeImg to console to see
Map.centerObject(aoi, 11);
Map.addLayer(changeImg.select(['mag']), magVizParms, 'Magnitude of Change');
Map.addLayer(changeImg.select(['yod']), yodVizParms, 'Year of Detection');
// export change data to google drive
var region = aoi.buffer(1000).bounds();
var exportImg = changeImg.clip(region).unmask(0).short();
Export.image.toDrive(
{image: exportImg,description: 'lt-gee_disturbance_map',
folder: 'lt-gee_disturbance_map',
fileNamePrefix: 'lt-gee_disturbance_map',
region: region,
scale: 30,
crs: 'EPSG:5070',
maxPixels: 1e13});
It is throwing an error: Line 75: GeometryConstructors.Polygon: LinearRing requires at least 3 points. I am not sure what I am doing wrong here. Thank you for your help.
I am displaying a bar chart in my android app with data labels. The highchart excepts only numeric value, although I have tried to use string as values the chart doesn't render. Below is my code
public void golyChartView(Number prev,Number curr)
{
HIOptions options = new HIOptions();
HIChart chart = new HIChart();
chart.setType("bar");
options.setChart(chart);
HITitle title = new HITitle();
title.setText("GOLY");
options.setTitle(title);
HISubtitle subtitle = new HISubtitle();
subtitle.setText("Growth Over Last Year");
options.setSubtitle(subtitle);
HIXAxis xaxis = new HIXAxis();
String[] categories = new String[] { "2020", "2021"};
xaxis.setCategories(new ArrayList<>(Arrays.asList(categories)));
options.setXAxis(new ArrayList<HIXAxis>(){{add(xaxis);}});
HIYAxis yaxis = new HIYAxis();
yaxis.setMin(0);
yaxis.setTitle(new HITitle());
yaxis.getTitle().setText("Sale Amount");
yaxis.getTitle().setAlign("high");
yaxis.setLabels(new HILabels());
yaxis.getLabels().setOverflow("justify");
options.setYAxis(new ArrayList<HIYAxis>(){{add(yaxis);}});
HITooltip tooltip = new HITooltip();
options.setTooltip(tooltip);
HILegend legend = new HILegend();
legend.setLayout("vertical");
legend.setAlign("right");
legend.setVerticalAlign("top");
legend.setX(-30);
legend.setY(40);
legend.setFloating(true);
legend.setBorderWidth(1);
legend.setBackgroundColor(HIColor.initWithHexValue("FFFFFF"));
legend.setShadow(true);
options.setLegend(legend);
HICredits credits = new HICredits();
credits.setEnabled(false);
options.setCredits(credits);
HIBar bar1 = new HIBar();
bar1.setName("Sale Value");
Number[] bar1Data = new Number[]{prev,curr};
bar1.setColorByPoint(true);
bar1.setData(new ArrayList<>(Arrays.asList(bar1Data)));
float numb = (((float)curr - (float)prev)/(float)prev)*100;
String percentage = String.valueOf(numb);
HIDataLabels dataLabels = new HIDataLabels();
dataLabels.setEnabled(true);
ArrayList<HIDataLabels> dataLabelsList = new ArrayList<>();
dataLabelsList.add(dataLabels);
bar1.setDataLabels(dataLabelsList);
HIDataLabels hiDataLabels = new HIDataLabels();
hiDataLabels.setEnabled(true);
HILegend hiLegend = new HILegend();
hiLegend.setEnabled(false);
options.setLegend(hiLegend);
options.setSeries(new ArrayList<>(Collections.singletonList(bar1)));
HIExporting exporting = new HIExporting();
exporting.setEnabled(false);
options.setExporting(exporting);
golyChart.setOptions(options);
golyChart.update(options,true,false);
}
Output
What I want to do?
As shown in the above code I have a string of percentage, that I want to add below the second bar Like below
I am stuck to it and don't know what to do
Any help would be highly appreciated.
You could use text Renderer to add text next to the bar.
I don't know android-highcharts but in javascript here an example
let customLabel,
labelInit = false;
Highcharts.chart('container', {
chart: {
type: 'bar',
events: {
render: function () {
const chart = this,
point = chart.series[0].data[1];
// prevent multiple label creation if used in render event but useless in "load" event
if (labelInit) customLabel.destroy();
customLabel = chart.renderer.text('+25 %', point.shapeArgs.height, point.tooltipPos[1] + chart.series[0].itemWidth + 10)
.add()
.attr({
zIndex: 3
});
labelInit = true;
}
}
},
title:{
text: "GOLY"
},
plotOptions: {
bar: {
grouping: false
}
},
xAxis: {
type: "category",
categories: ["2020", "2021"]
},
series: [{
data: [200, 400],
colorByPoint: true
}]
});
How to get the difference image of this month and the previous month in Google Earth Engine with a smart way?
study area 25E-75E,5S-35N。
// study area 25E-75E,5S-35N。
var geometry =
ee.Geometry.Polygon(
[[[25, 35],
[25, 5],
[75, 5],
[75, 35]]], null, false);
var regions = ee.FeatureCollection([
ee.Feature(geometry)
]);
// imgCol
var now = ee.Date(Date.now());
var NDVICollection=ee.ImageCollection('MODIS/006/MOD13Q1')
.filterDate('2010-01-01',now)
.filterBounds(regions)
.select('NDVI');
var col = NDVICollection.map(function(img){
return img.multiply(0.0001)
.copyProperties(img,['system:time_start','system:time_end']);
});
// grouped by month
var months = ee.List([11,12,1,2]);
var byMonth = ee.ImageCollection.fromImages(
months.map(function (m) {
return col.filterDate('2019-11-01',now).filter(ee.Filter.calendarRange(m, m, 'month'))
.select('NDVI').mean()
.set('month', m);
}));
mask
var meanNDVI = byMonth.reduce(ee.Reducer.mean());
var mask = meanNDVI.gt(0.1);
Create difference image
**var img12 = byMonth.filter(ee.Filter.eq('month', ee.Number(12))).first().updateMask(mask);
var img11 = byMonth.filter(ee.Filter.eq('month', ee.Number(11))).first().updateMask(mask);
var img1 = byMonth.filter(ee.Filter.eq('month', ee.Number(1))).first().updateMask(mask);
var img2 = byMonth.filter(ee.Filter.eq('month', ee.Number(2))).first().updateMask(mask);
var ndviChange_12 = img12.subtract(img11).set('name','ndviChange_12');
var ndviChange_1 = img1.subtract(img12).set('name','ndviChange_1');
var ndviChange_2 = img12.subtract(img1).set('name','ndviChange_2');
var ndviChange = ee.ImageCollection([ndviChange_12,ndviChange_1,ndviChange_2]);**
I want make it much more smart, what should I do? make a function or something else?
Show the image
Map.centerObject(regions);
Map.addLayer(byMonth);
Map.addLayer(ndviChange);
I think the solution is to use iterate on your byMonth collection . Check this example in the documentations.
https://developers.google.com/earth-engine/ic_iterating
I am having issues rotating my symbol around a specific pivot point.
Here is my code :
var path_tank_left_track = new Path({
segments: [[0,0], [10, 0], [10,40], [0,40]], strokeColor: 'black',
closed: true
});
var path_tank_right_track = new Path({
segments: [[40,0], [50, 0], [50,40], [40,40]], strokeColor: 'black',
closed: true
});
var path_tank_body = new Path({
segments: [[10,5], [40,5], [40,35], [10,35]], strokeColor: 'black',
closed: true
});
var path_tank_gun = new Path({
segments: [[23,15], [23,0], [27, 0], [27, 15]],
strokeColor: 'black',
pivot: [25,15],
name: 'gun'
});
var path_arena_separation = new Path(new Point(view.size.width/2,0),
new Point(view.size.width/2, view.size.height));
path_arena_separation.strokeColor = 'black';
path_arena_separation.closed = true;
var whole_tank = new Group();
whole_tank.addChild(path_tank_left_track);
whole tank.addChild(new Point(5,20)); // trying to add the middle of the left track pivot point
whole_tank.addChild(path_tank_body);
whole_tank.addChild(path_tank_right_track);
whole tank.addChild(new Point(50,20)); // trying to add the middle of the right track pivot point
whole_tank.addChild(path_tank_gun);
// Create a symbol definition from the path:
var definition = new SymbolDefinition(whole_tank);
var instance1 = definition.place();
instance1.position = new Point(view.size.width/4, view.size.height/2);
var instance2 = definition.place();
instance2.position = new Point(3*view.size.width/4, view.size.height/2);
function onFrame(event) {
instance1.rotate(1, instance1.definition.item.children[1]);
}
As you can see, at the onFrame function, I'm trying to rotate the instance by 1 degree every frame around the point I created earlier. But I get an error saying the item_remove is not a function in the paper-full.js.
I'm confused, I tried to create a path with a single point and add it to the group but it did not let me.
If I modify the code to make the gun rotate on it's pivot instead, it does work :
function onFrame(event) {
instance1.definition.item.children['gun'].rotate(1, instance1.definition.item.children['gun'].pivot);
}
The gun does rotate around the proper pivot and the pivot stays attached to the symbol even if the symbol moves around. How could I achieve that behavior but turning the whole tank around a specific point relative to the center of the tank?
Thank you for your help, let me know if I should include more detail.
Your code is crashing because you try to add a point (and not a path containing a single point as you seems to be trying to) as a group child, which is not what API expects.
To create a path containing a single point, you have to do this:
var path = new Path(new Point(x,y));
But I think the idea of adding a single point path as a child to later retrieve its position to use it as a pivot point is wrong in your case.
The fact that you are creating each tank as a Symbol implies that you won't have access to its own children.
You can instead, before placing your symbols, store 2 vectors: one from center to left and one from center to right. They will later help you calculating left / right track positions.
Here is a Sketch adapted from your code, demonstrating this.
var path_tank_left_track = new Path({
segments : [ [ 0, 0 ], [ 10, 0 ], [ 10, 40 ], [ 0, 40 ] ],
strokeColor: 'black',
closed : true
});
var path_tank_right_track = new Path({
segments : [ [ 40, 0 ], [ 50, 0 ], [ 50, 40 ], [ 40, 40 ] ],
strokeColor: 'black',
closed : true
});
var path_tank_body = new Path({
segments : [ [ 10, 5 ], [ 40, 5 ], [ 40, 35 ], [ 10, 35 ] ],
strokeColor: 'black',
closed : true
});
var path_tank_gun = new Path({
segments : [ [ 23, 15 ], [ 23, 0 ], [ 27, 0 ], [ 27, 15 ] ],
strokeColor: 'black',
pivot : [ 25, 15 ],
name : 'gun'
});
var path_arena_separation = new Path(new Point(view.size.width / 2, 0), new Point(view.size.width / 2, view.size.height));
path_arena_separation.strokeColor = 'black';
path_arena_separation.closed = true;
var whole_tank = new Group();
whole_tank.addChild(path_tank_left_track);
whole_tank.addChild(path_tank_left_track);
whole_tank.addChild(path_tank_body);
whole_tank.addChild(path_tank_right_track);
whole_tank.addChild(path_tank_gun);
// store vectors from bounds center to tracks middle points
var tankCenter = whole_tank.bounds.center;
var leftTrackCenter = new Point(5, 20);
var rightTrackCenter = new Point(50, 20);
var leftVector = leftTrackCenter - tankCenter;
var rightVector = rightTrackCenter - tankCenter;
// Create a symbol definition from the path:
var definition = new SymbolDefinition(whole_tank);
var instance1 = definition.place();
instance1.position = new Point(view.size.width / 4, view.size.height / 2);
var instance2 = definition.place();
instance2.position = new Point(3 * view.size.width / 4, view.size.height / 2);
function onFrame(event)
{
// calculate pivot point position
// first we rotate vector accordingly to instance current rotation
var rotatedVector = rightVector.rotate(instance1.rotation);
// then we add it to current tank center
var point = instance1.bounds.center + rotatedVector;
// turn right
instance1.rotate(1, point);
}
I have Yandex map tiles (Russian) working in Google Maps API v2 but something's not working in Google Maps API v3, see the following jsfiddle: http://jsfiddle.net/VkGjq/1/
Note that when switching between the Google road map and the Yandex tiles they don't line up & the marker is in the wrong position.
For Maps v2, I made an equivalent jsfiddle but it's broken since it needs an API key: http://jsfiddle.net/ggrgQ/1/
You can see similar code here, but you will have to navigate to Moscow manually as Yandex doesn't have any decent data outside of Russia: http://gpsloglabs.com/share/2367c16f3a0e75b05ac8a5529afba225dd929518/
I don't recall where I got the v3 code, but the constants appear to roughly correspond to the v2 version. Other than that, I don't understand what the projection is doing so I'm stuck.
Any ideas?
The code from the jsfiddle is as follows:
var center = new google.maps.LatLng(55.75, 37.62);
var mapOptions = {
zoom: 10,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map'), mapOptions);
new google.maps.Marker({map: map, position: center});
map.mapTypes.set("Yandex",
new google.maps.ImageMapType(
{getTileUrl: function(coord, zoom) {
return "http://vec0"+((coord.x+coord.y)%5)+".maps.yandex.net/tiles?l=map&v=2.16.0&x=" +
coord.x + "&y=" + coord.y + "&z=" + zoom + "";
},
tileSize: new google.maps.Size(256, 256),
isPng: true,
alt: "Yandex",
name: "Yandex",
projection: new YandexProjection(),
maxZoom: 17}));
map.setOptions({mapTypeControlOptions: {mapTypeIds: [google.maps.MapTypeId.ROADMAP, "Yandex"]} });
function YandexProjection() {
this.pixelOrigin_ = new google.maps.Point(128,128);
var MERCATOR_RANGE = 256;
this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
this.fromLatLngToPoint = function(latLng) {
function atanh(x) {
return 0.5*Math.log((1+x)/(1-x));
}
function degreesToRadians(deg) {
return deg * (Math.PI / 180);
}
function bound(value, opt_min, opt_max) {
if (opt_min != null) value = Math.max(value, opt_min);
if (opt_max != null) value = Math.min(value, opt_max);
return value;
}
var origin = this.pixelOrigin_;
var exct = 0.0818197;
var z = Math.sin(latLng.lat()/180*Math.PI);
return new google.maps.Point(origin.x + latLng.lng() *this.pixelsPerLonDegree_,
Math.abs(origin.y - this.pixelsPerLonRadian_*(atanh(z)-exct*atanh(exct*z))));
};
this.fromPointToLatLng = function(point) {
var origin = this.pixelOrigin_;
var lng = (point.x - origin.x) / this.pixelsPerLonDegree_;
var latRadians = (point.y - origin.y) / -this.pixelsPerLonRadian_;
var lat = Math.abs((2*Math.atan(Math.exp(latRadians))-Math.PI/2)*180/Math.PI);
var Zu = lat/(180/Math.PI);
var Zum1 = Zu+1;
var exct = 0.0818197;
var yy = -Math.abs(((point.y)-128));
while (Math.abs(Zum1-Zu)>0.0000001){
Zum1 = Zu;
Zu = Math.asin(1-((1+Math.sin(Zum1))*Math.pow(1-exct*Math.sin(Zum1),exct))
/ (Math.exp((2*yy)/-(256/(2*Math.PI)))*Math.pow(1+exct*Math.sin(Zum1),exct)));
}
if (point.y>256/2) {
lat=-Zu*180/Math.PI;
} else {
lat=Zu*180/Math.PI;
}
return new google.maps.LatLng(lat, lng);
};
return this;
}
It turns out that the projection property can't be set via the ImageMapTypeOptions and has to be assigned after the ImageMapType has been constructed, this jsfiddle now works: http://jsfiddle.net/VkGjq/2/
var yandexMapType = new google.maps.ImageMapType(
{getTileUrl: function(coord, zoom) {
return "http://vec0"+((coord.x+coord.y)%5)+".maps.yandex.net/tiles?l=map&v=2.16.0&x=" +
coord.x + "&y=" + coord.y + "&z=" + zoom + "";
},
tileSize: new google.maps.Size(256, 256),
isPng: true,
alt: "Yandex",
name: "Yandex",
maxZoom: 17});
// projection is ignored if passed to MapTypeOptions
yandexMapType.projection = new YandexProjection();
map.mapTypes.set("Yandex", yandexMapType);
By license agreement you can't use yandex maps without yandex api. You can't use yandex tiles in leaflet.
You need to wrap yandex api or use http://leafletjs.com/plugins.html
Or write own a wrapper.
Example https://all-maps.herokuapp.com/
https://github.com/artamonovdev/all-maps