I'm trying to correctly save an OpenLayer 3 Map layer created by a user in order to display it another map using geoJSON, but I'm having troubles with this.
On the client side I save the dinamic layer in this function:
function addInteractions() {
draw = new ol.interaction.Draw({
source: source,
type: typeSelect.value
});
draw.on("drawend", function(e) {
var f = e.feature;
features.push(f);
geoJson = format.writeFeatures(features);
console.log(geoJson);
document.getElementById('js-textarea').value = geoJson;
});
map.addInteraction(draw);
snap = new ol.interaction.Snap({source: source});
map.addInteraction(snap);
}
Then the geoJSON object is saved into a .json file, but when I try to display it, it doesn't appear on the map.
Here his my display function:
var geoDataUrl = '/data/' + '{{percorso._id}}' + '.json';
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: geoDataUrl,
format: new ol.format.GeoJSON()
}),
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [raster, vectorLayer],
target: 'map',
view: new ol.View({
center: {{#if percorso.mapCenter}}[{{percorso.mapCenter}}] {{else}} ol.proj.transform([9.688053, 45.362760], 'EPSG:4326', 'EPSG:3857'){{/if}},
zoom: {{#if percorso.zoomLevel}}{{percorso.zoomLevel}} {{else}} 13{{/if}}
})
});
I also tested the display function with other layers (for example the provided one on the OpenLayer examples website ) and it works fine
On the server side I save the geoJSONobject with this function, where oggetto_mappa is the dinamic geoJSON object:
var jsonMappa = JSON.stringify(eval("(" + oggetto_mappa + ")"));
require("fs").writeFile("./public/data/" + id_perc + ".json", jsonMappa, 'utf8', function(f_err) {
if(f_err)
console.log(f_err);
});
For refernce this is what my function saves onto the .json file:
{
"type":"FeatureCollection",
"features":[
{
"type":"Feature",
"id" : "aa",
"geometry":
{
"type":"LineString",
"coordinates":[
[1073328.751180445,5680150.227413875],
[1077857.6451063417,5682481.556776573],
[1070385.9255914658,5679156.546046168],
[1076825.7452244917,5680226.66444216],
[1073328.751180445,5680169.336670946]
]
},
"properties":null
},
{
"type":"Feature",
"id" : "ab",
"geometry":
{
"type":"LineString",
"coordinates":[
[1073328.751180445,5680169.336670946],
[1071628.0273010998,5677130.96479661]
]
},
"properties":null}
]
}
To get things working, replace
geoJson = format.writeFeatures(features)
with
geoJson = format.writeFeatures(features, {featureProjection: 'EPSG:3857'})
You may wonder why?
When you draw in OpenLayers, you are drawing in the projection of the map (the default is EPSG:3857) whereas when you consume a GeoJSON the expected projection is EPSG:4326.
See the API documentation from ol.format.GeoJSON writeFeatures to understand better
Some additional informations:
when you consume the GeoJSON from your drawing as the coordinates are not in decimal degrees (EPSG:4326) but in meters (EPSG:3857)
the order of magnitude for coordinates is different (millions for EPSG:3857 and less than some hundred for EPSG:4326) without accounting for the positive/negative coordinates
Related
Is there a way to get smooth gradient from the lighting?
I'm creating a survival game using PhaserJs 3. I'm using the LightsManager and a tileset I modified from one of the example tilesets included in the examples.
Currently the tile grid is visible because of how the lighting is working with the tiles.
If possible, I would like to have the lighting be smooth similar to the picture below:
My grass tile is 32x32:
and the normal map is the following image
which was generated using this normal map generator site.
var config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
pixelArt: true,
backgroundColor: '#000000',
scene: {
preload: preload,
create: create,
update: update,
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x:0 },
debug: false
}
},
};
var light;
var layer;
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('tiles', ['assets/tilemap.png','assets/tilemap_n.png']);
...
}
function create ()
{
var level = [ // The grass tile is #29 in the tileset
[29,29,29,29,29,29],
[29,29,29,29,29,29],
[29,29,29,29,29,29],
[29,29,29,29,29,29],
[29,29,29,29,29,29],
[29,29,29,29,29,29]]
var map = this.make.tilemap({ data: level, tileWidth: 32, tileHeight: 32 });
var tiles = map.addTilesetImage('tiles');
layer = map.createStaticLayer(0, tiles, 0, 0).setScale(2)
layer.setPipeline('Light2D');
light = this.lights.addLight(390,223.3, 150).setIntensity(.8);
}
I'm not sure if this is the best (or most performant) way, but you could use this plugin to create a post pipeline blur.
here a working demo of this plugin: https://codepen.io/rexrainbow/pen/zYzzYVw
Basically you would have to load the plugin, in preload:
function preload (){
...
this.load.plugin('rexkawaseblurpipelineplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexkawaseblurpipelineplugin.min.js', true);
}
And apply the plugin in to the specific camera, or gameobject:
function create (){
var postFxPlugin = this.plugins.get('rexkawaseblurpipelineplugin');
var postFxPipeline = postFxPlugin.add(this.cameras.main, {
blur: 1,
quality: 3
});
...
}
Or you could fake, the gradient with multiple lights and may be add a specific ambientColor:
light1 = this.lights.addLight(390,300, 150, 0xffffff, .80);
light2 = this.lights.addLight(390,300, 250, 0xffffff, .75);
light3 = this.lights.addLight(390,300, 350, 0xffffff, .70);
this.lights.enable().setAmbientColor(0x555555);
i need your help please.
I would like to be able to click on a point added on an ArcGis map so that when I click on it I am redirected to another web page
I have been following the tutorials:
https://developers.arcgis.com/javascript/latest/display-a-map/
Display a map
Add a point
add a feature layer
Display a popup
This is the code so far:
require([
"esri/config",
"esri/Map",
"esri/views/MapView",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/layers/FeatureLayer"
], function(esriConfig,Map, MapView, Graphic, GraphicsLayer, FeatureLayer) {
esriConfig.apiKey = "YOUR_KEY";
const map = new Map({
basemap: "arcgis-topographic"
});
const view = new MapView({
container: "DivCarte",
map: map,
center: [-83.54500,19.02700],
zoom: 6
});
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
const point = { //Create a point
type: "point",
longitude: -86.900000,
latitude: 21.201278
};
const simpleMarkerSymbol = {
type: "simple-marker",
color: [226, 119, 40], // Orange
outline: {
color: [255, 255, 255], // White
width: 1
}
};
const popupTemplate = {
title: "Cancun",
content: "<a href=http://travelwithnico.com>Site</a>"
}
const attributes = {
Name: "AttGraphic",
Description: "Ilalala"
}
const pointGraphic = new Graphic({
geometry: point,
symbol: simpleMarkerSymbol,
attributes: attributes,
popupTemplate: popupTemplate
});
graphicsLayer.add(pointGraphic);
I managed to open a popup showing the link but it opens on a new tab.
How can I force it to move to the link in the same window?
Thank you for your help.
Nico
Have you tried inlining a JavaScript inside an onclick event? Something like this:
...
content: 'Site'
...
I'm not sure if this will work, but it worths trying.
My gpx file already contains elevation information for each trkpt and I can augment this with a speed for each trkpt. I would like to represent the elevation or the speed at each trkpt by varying the color of the track. For instance: slow is blue, fast is red.
How can I do this?
And this probably means: Which files and functions in Openlayers do I have to change to do this?
You can try the ol/style/FlowLine of ol-ext to achieve this.
Using this style, you can change the with/color of the feature along the line using a function. This example show how to: http://viglino.github.io/ol-ext/examples/style/map.style.flowline2.html.
You just have to calculate the width (or color) along the feature geometry varying according the speed or altitude:
const flowStyle = new ol.style.FlowLine({
width: function(f, step) {
// calculate the with of the feature f at the given step
// step is the curvilinear abscissa between 0,1
// (0: first coordinate, 1: last one)
const width = ...
return width;
}
});
#+
You should go with a stylefunction for the vector layer:
https://openlayers.org/en/v4.6.5/apidoc/ol.html#.StyleFunction
This function is checked for each feature to be displayed on the vector layer and the related style can be set/returned programmatically. For example:
function gpxStyle(feature) {
var style = null;
if (feature.get("speed")>="100") {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
stroke: new ol.style.Stroke({
color: 'red',
width: 2
}),
fill: new ol.style.Fill({
color: 'red'
})
})
});
}
else {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
stroke: new ol.style.Stroke({
color: 'blue',
width: 2
}),
fill: new ol.style.Fill({
color: 'blue'
})
})
});
}
return [style];
}
var gpxLayer = new ol.layer.Vector({
source: new ol.source.Vector(),
style: gpxStyle
});
How to keep all the qtips inside a container (I have already tried position.container, position.viewport and position.adjust.method) without any luck, my best guess is that I am not using them correctly.
Update:1 I have created a sample app with more details on below url
http://secure.chiwater.com/CodeSample/Home/Qtip
Update:2 I have created jsfiddle link too. http://jsfiddle.net/Lde45mmv/2/
Please refer below screen shot for layout details.
I am calling the area shown between two lines as $container in my js code.
So far I have tried tweaking viewport, adjust method but nothing helped. I am hoping this is possible and I would greatly appreciate any help.
Below is my javascript code which creates qtip2.
//Now create tooltip for each of this Comment number
$('#cn_' + num).qtip({
id: contentElementID,
content: {
text: .....
var $control = $('<div class="qtip-parent">' +
' <div class="qtip-comment-contents">......</div>' +
' <div class="clearfix"></div>' +
' <div class="qtip-footer"><span class="qtip-commenter">...</span><span class="pull-right">...</span></div>' +
'</div>'
);
return $control;
},
button: false
},
show: 'click',
hide: {
fixed: true,
event: 'unfocus'
},
position: {
my: 'top right',
at: 'bottom right',
target: $('#cn_' + num),
container: $container,
//viewport: true,
adjust: { method: 'shift none' }
},
style: {
tip: {
corner: true,
mimic: 'center',
width: 12,
height: 12,
border: true, // Detect border from tooltip style
//offset: 25
},
classes: 'qtip-comment'
},
events: {
show: function (event, api) {
...
},
hide: function (event, api) {
...
}
}
});
Example of jalopnik page which shows what I am looking for (FWIW jalopnik example doesn't use qtip2).
I don't think qtip API supports this functionality. I ended up re-positioning the tooltip on visible event.
I have updated the demo page and jsfiddle link below is code for doing this.
events: {
visible: function (event, api) {
var $qtipControl = $(event.target);
$qtipControl.css({ 'left': contentPosition.left + "px" });
var $qtipTipControl = $qtipControl.find(".qtip-tip");
var $target = api.get("position.target");
$qtipTipControl.css({ "right": 'auto' });
//I am using jquery.ui position
$qtipTipControl.position({
my: "center top",
at: "center bottom",
of: $target
});
}
}
Problem with this approach is that there is noticeable jump when I re-position the qTip. But in lack of any other option for time being I will settle with this.
The ideal approach would be to allow callback method thru position.adjust currently it only supports static values for x and y, if a method was allowed here it would make things much smoother.
I need to hide US on geo chart, when region is set to Canada:
google.load('visualization', '1', {'packages': ['geochart']});
google.setOnLoadCallback(drawVisualization);
function drawVisualization() {var data = new google.visualization.DataTable();
data.addColumn('string', 'Country');
data.addColumn('number', 'Value');
data.addColumn({type:'string', role:'tooltip'});var ivalue = new Array();
data.addRows([[{v:'CA-BC',f:'CA-BC'},0,'Test']]);
var options = {
backgroundColor: {fill:'#FFFFFF',stroke:'#FFFFFF' ,strokeWidth:0 },
colorAxis: {minValue: 0, maxValue: 0, colors: ['#0000ff',]},
legend: 'none',
backgroundColor: {fill:'#FFFFFF',stroke:'#FFFFFF' ,strokeWidth:0 },
datalessRegionColor: '#f5f5f5',
displayMode: 'markers',
enableRegionInteractivity: 'true',
resolution: 'provinces',
region:'CA',
keepAspectRatio: true,
width:700,
height:500,
tooltip: {textStyle: {color: '#444444'}, trigger:'focus'}
};
var chart = new google.visualization.GeoChart(document.getElementById('visualization'));
chart.draw(data, options);
}
http://jsfiddle.net/jk171505/VJtBR/
With the API options, you can't really do it.
You can use advanced CSS selectors to hide the SVG shapes.
Add this CSS and it will hide the US shapes:
#visualization path:nth-child(237), #visualization path:nth-child(236) {
display:none;
}
http://jsfiddle.net/cmoreira/mMadX
I have built a page with some information on how to use this and other CSS techniques with the Google Geochart API. In case it helps, here's the link: http://cmoreira.net/interactive-world-maps-demo/advanced-customization/