javascript config file for openlayers - javascript

I am new to OpenLayers. I am trying to figure out what is the best way to have a configuration file for the map I am creating.
For example, I am creating a map with the following style :
var defaultStyle = new OpenLayers.Style(
{
pointRadius: 10,
fillColor: "yellow",
strokeColor:"#0500bd",
strokeWidth:2,
fillOpacity:0.4,
labelXOffset: "${xOffset}",
labelYOffset: "${yOffset}",
labelAlign: "${align}"
});
I would like to have the pointRadius and fillColor in a config file so I don't have to modify my source code but just the config file.
Shall I create a JS file; config.js with the following content:
var config = {
map:{
style: {
pointRadius: 10,
fillColor: "yellow"
},
},
};
And then, in my other JS that create the style, does:
var defaultStyle = new OpenLayers.Style(
{
pointRadius: config.map.style.pointRadius,
fillColor: config.map.style.fillColor,
strokeColor:"#0500bd",
strokeWidth:2,
fillOpacity:0.4,
labelXOffset: "${xOffset}",
labelYOffset: "${yOffset}",
labelAlign: "${align}"
});
What is recommended?

I cannot say what is "recommended". However Your solution is very similar to the way we do it on our current project. We have been doing like that for over a year have had a lot of success.
We save the configuration in a database as a JSON array, and then allow JS to parse the array.
Also you can then use the OpenLayers.Util.extend function to extend your style:
var config = {
map:{
style: {
pointRadius: 10,
fillColor: "yellow"
},
},
};
var defaultStyle = new OpenLayers.Style(OpenLayers.Util.extend({
strokeColor:"#0500bd",
strokeWidth:2,
fillOpacity:0.4,
labelXOffset: "${xOffset}",
labelYOffset: "${yOffset}",
labelAlign: "${align}"
},config.map.style));

I would do something like this:
var config = {
default_map_style: {
pointRadius: 10,
fillColor: 'yellow'
}
};
And then instead of using it one by one, I would just extend the default map style object with additional properties that I want to use on the fly like so:
var defaultStyle = new OpenLayers.Style(
$.extend({}, config.default_map_style, {
strokeColor: '#0500bd'
}
);
I'm using jQuery.extend above but you can find another implementation of extend in Underscore or Lo-dash if you'd rather not use jQuery. Note that it is important we pass a new object as the first parameter of extend as we don't want to change the default_map_style object.

Related

Trying to reactively update chart data, however, the chart does not reflect the changes. Vue.js

Sadly, I am facing some Vue.js reactivity issues yet again. Currently my code renders the chart once on mounted() and then it re-renders the chart every time the data updates thanks to a watcher. This does work (aside from the fact that I'm not sure how to remove the previously rendered charts), however, I am not sure if this is the correct way of doing the update considering I am using Vue. Having the already rendered chart update on data update seems like a better option to me instead of rendering a whole new chart and deleting the old one.
I tried changing the data using this.data = the new data, however, I know that this will not make the object reactive. I also tried using this.$set as is explained here - https://v2.vuejs.org/v2/guide/reactivity.html , however, I am not achieving anything with it. I might not be using it correctly though. I also tried changing just one property of the object which also wasn't affecting the chart.
<template>
<div id="app">
<button #click="updateChart()">X</button>
<canvas id="myChart"></canvas>
</div>
</template>
<script>
export default {
data: function() {
return {
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}],
}
}
},
methods: {
updateChart(){
this.data = {
labels: ['Red', 'Red', 'Red', 'Red', 'Red', 'Red'],
datasets: [{
label: 'EYOOOOOOOOOOOOOO',
data: [6, 7, 8, 9, 10, 11]
}],
}
/*this.$set(this.data, {
labels: ['Red', 'Red', 'Red', 'Red', 'Red', 'Red'],
datasets: [{
label: 'Please Work',
data: [6, 7, 8, 9, 10, 11]
}],
}))*/
/*this.$set(this.data, 'labels', ['Red', 'Red', 'Red', 'Red', 'Red', 'Red'])*/
},
renderChart(data, options){
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
}
},
mounted() {
this.renderChart(this.data, this.options)
},
watch: {
data: function() {
this.renderChart(this.data, this.options)
}
}
}
Try using a deep watcher on data.
{
watch: {
data: {
handler: function(value) {
this.renderChart(this.data, this.options)
},
deep: true,
}
}
}
BTW it is confusing to have a data property called data... I suggest changing it to chartData.
In Vue, only the top level object properties will trigger reactive changes. deep will cause nested objects (in your case labels and datasets) to also trigger an update. Most cases do not need deep, so to eliminate the overhead you need to add it if you want it.
Make sure you do not add any new properties to an existing data object without going through Vue.set. That is the next most common issue when the UI does not update to data changes.
From: https://v2.vuejs.org/v2/guide/reactivity.html
Sometimes you may want to assign a number of properties to an existing
object, for example using Object.assign() or _.extend(). However, new
properties added to the object will not trigger changes. In such
cases, create a fresh object with properties from both the original
object and the mixin object:
Try updating your this.data by doing this:
this.data = Object.assign({}, {
labels: ['Red', 'Red', 'Red', 'Red', 'Red', 'Red'],
datasets: [{
label: 'Please Work',
data: [6, 7, 8, 9, 10, 11]
}],
})

Changing style of map elements dynamically

I am attempting to change the style of a number of map elements on the fly, without success. By on the fly I mean changing the color of a map element, the water mass for instance, dynamically from a computed color. Using Tangram but open to other engines if there is a better solution. Since Tangram uses a YAML file to style the various elements, I am using inline Javascript on the scene (YAML) file. In other words, instead of giving it a fixed color, I want to compute the color (from an image). Instead of this:
water:
draw:
polygons:
color: "blue"
I am doing something along these lines (further complicated because I am using Vue Router):
water:
draw:
polygons:
color: function() { return this.colors[0]; }
computedColors is computed in a mixing, then broadcasted to the appropriate route:
var colorize = {
data: function () {
return {
computedColors: []
};
},
created: function () {
this.getColors();
},
methods: {
getColors: function () {
...
self.computedColors = [
...
];
self.$broadcast('parent-colors', self.computedColors);
...
};
};
}
Here is the route:
router.map({
'/map': {
name: 'map',
component: Vue.extend({
template: '#map',
mixins: [colorize],
data: function () {
return {
colors: []
};
},
events: {
'parent-colors': function (computedColors) {
this.colors = computedColors;
}
},
ready: {
var map = L.map('map');
var layer = Tangram.leafletLayer({
scene: './tiles/scene.yaml'
});
layer.addTo(map);
map.setView([40.70531887544228, -74.00976419448853], 15);
}
});
Any hints on what I may be doing wrong appreciated.
UPDATE
I am getting an error of sorts. It is related with Tangram but not quite able to figure out what it is exactly. Seems to be an issue with the parsing of the YAML file. If I change this in my scene.yaml:
water:
draw:
polygons:
color: function() { return this.colors[0]; }
With this:
water:
draw:
polygons:
color: function() { return this.color1; }
I get no errors but unfortunately the water mass still isn't assigned any color either.
Of course, I had to change these lines in the map route instance too:
data: function () {
return {
color1: ''
};
},
...
events: {
'parent-colors': function (computedColors) {
this.color1 = computedColors[0];
}
}
The following doesn't offer a solution to the specific problem of styling a Tangram map on the fly (which Yaml doesn't seem to easily allow), but it partially answers the question of how to style map vectors dynamically. It implements the plugin Leaflet.VectorGrid and assigns properties to layers programmatically through the vectorTileLayerStyles method (accomplished in the example below with color: self.colors[6]).
L.vectorGrid.slicer(countries, {
rendererFactory: L.svg.tile,
vectorTileLayerStyles: {
sliced: function() {
return {
stroke: true,
color: self.colors[6],
weight: 0.5,
};
}
},
}).addTo(map);
The variable countries is really just a GeoJson with var countries = added to it, something along these lines:
var countries = {
"type": "FeatureCollection",
"features": [
{ "type": "Feature"
(...)
}
]
};
It's a straightforward solution and it works perfectly with small amounts of data, but since it's a client-side solution it's heavy on the browser when dealing with bigger data sets. Still, it may be useful for those who may be looking for a simple way to style a simplified world map or a limited map area on the fly.
UPDATE
A more performant solution is to use a tile server. The example below implements t-rex, with canvas renderer L.canvas.tile in the rendererFactory option instead of L.svg.tile and protobuf:
var lines = "http://127.0.0.1:6767/lines/{z}/{x}/{y}.pbf";
var multilinestrings = "http://127.0.0.1:6767/multilinestrings/{z}/{x}/{y}.pbf";
var multipolygons = "http://127.0.0.1:6767/multipolygons/{z}/{x}/{y}.pbf";
var vectorTileStyling = {
lines: {
weight: .8,
fillColor: this.colors[1],
color: this.colors[1],
fillOpacity: .8,
opacity: .8
},
multilinestrings: {
weight: .8,
fillColor: this.colors[2],
color: this.colors[2],
fillOpacity: .8,
opacity: .8
},
multipolygons: {
fill: true,
weight: .8,
fillColor: this.colors[3],
color: this.colors[3],
fillOpacity: .8,
opacity: .8,
}
};
var externalVectorTileOptions = {
rendererFactory: L.canvas.tile,
vectorTileLayerStyles: vectorTileStyling,
maxZoom: 16,
minZoom: 14
};
L.vectorGrid.protobuf(lines, externalVectorTileOptions).addTo(map);
L.vectorGrid.protobuf(multilinestrings, externalVectorTileOptions).addTo(map);
L.vectorGrid.protobuf(multipolygons, externalVectorTileOptions).addTo(map);

JVectorMap Multimap drill down has different style when drilled down, how can I change this style as well?

This question was asked here as well maybe a year ago, but no answer was provided. I'd like to know how I can make the "drilled-down" map have the same style and background as my main map.
var regionStyling9 = { // This style is set to the main map's regionStyle
initial: {
fill: '#E9E9E9',
stroke: '#505050',
"fill-opacity": 1,
"stroke-width": 1,
"stroke-opacity": 1
},
hover: { fill: "#4DB870" }
};
$(function() {
new jvm.MultiMap({
container: $('#Chart9Map'),
maxLevel: 1,
main: {
map: 'us_aea_en',
backgroundColor: '#fff',
regionStyle: regionStyling9, // Here I set the top level style to the main map
series: {
regions: [{ values: stateMapData, scale: ['#cce2ec', '#006593'], normalizeFunction: 'polynomial' }]
}
},
mapUrlByCode: function(code, multiMap) {
return '../Scripts/JVectorMap/jquery-jvectormap-data-' +
code.toLowerCase() +
'-' +
multiMap.defaultProjection +
'-en.js';
}
});
});
How can I affect the style of the secondary chart like I did for the main chart?
According to the jVectorMap MultiMap Documentation, there is only config for the main map, no other object for the drill down maps...
I know what you mean, I also could not find this info. It is very strange the library doesnt handle this. Its such a well produced package, yet seems to me missing some basics.
Assuming you arent using the free version, the license says you are allowed to modify the code.
Open up the jquery-jvectormap.js file (prettify it is needed).
At the bottom you'll see the lines:
currentMap.params.container.hide(), that.maps[name] ? that.maps[name].params.container.show() : that.addMap(name, {
map: name,
multiMapLevel: currentMap.params.multiMapLevel + 1
}), that.history.push(that.maps[name]), that.backButton.show()
Change this so settings from the main map are passed down to the children (so just add the 3 extra lines):
currentMap.params.container.hide(), that.maps[name] ? that.maps[name].params.container.show() : that.addMap(name, {
backgroundColor: that.params.main.backgroundColor,
series: that.params.main.series,
onRegionTipShow: that.params.main.onRegionTipShow,
map: name,
multiMapLevel: currentMap.params.multiMapLevel + 1

Mootools options: how to change/overwrite an options property in an event function?

I have a class constructor that produces a series of animated radial progress bars, and outside of the constructor the elementSize property is assigned via the variables of options shown below. Each set of options assigns a different element size to the radial progress bars when they load in the browser. The four values shown below are from the first index in an array.
I am completely new to mootools and am struggling to figure out how I could change individual elementSize properties to each of my radial progress bars from here. I have 2 buttons with onclick events that go forward and backward through an array of values, so what I want to do is to call the elementSize option(s) and change the value of x depending on whether the user clicks forward (x++) or backward (x--).
Is there a way to do this in my buttons function? Or does it need to be included in my code by some other means?
var RPBoptionsB1 = {
backgroundColor: '#fff',
borderColor: '#1895cd',
borderWidth: '10',
elementSize: 90+(arrayStatsB[x][0]/45.775),
fontColor: '#5f6f7e',
overlayColor: '#fff',
animateText: true
};
var RPBoptionsB2 = {
backgroundColor: '#fff',
borderColor: '#1895cd',
borderWidth: '10',
elementSize: 90+(arrayStatsB[x][1]/45.775),
fontColor: '#5f6f7e',
overlayColor: '#fff',
animateText: true
};
var RPBoptionsB3 = {
backgroundColor: '#fff',
borderColor: '#1895cd',
borderWidth: '10',
elementSize: 90+(arrayStatsB[x][2]/45.775),
fontColor: '#5f6f7e',
overlayColor: '#fff',
animateText: true
};
var RPBoptionsB4 = {
backgroundColor: '#fff',
borderColor: '#1895cd',
borderWidth: '10',
elementSize: 90+(arrayStatsB[x][3]/45.775),
fontColor: '#5f6f7e',
overlayColor: '#fff',
animateText: true
};
//-----------------------------------------
var rpbArrayB = {
rpbB1: new RadialProgressBar($('rpbB1'), RPBoptionsB),
rpbB2: new RadialProgressBar($('rpbB2'), RPBoptionsB),
rpbB3: new RadialProgressBar($('rpbB3'), RPBoptionsB),
rpbB4: new RadialProgressBar($('rpbB4'), RPBoptionsB)
};
Thanks in advance.
In Mootools it is common to put options in the options object (http://mootools.net/docs/core/Class/Class.Extras#Options:setOptions).
Take this example:
var MyClass = new Class({
Implements: Options,
options: {
elementSize: 10
},
initialize: function(options){
this.setOptions(options);
}
});
var instance1 = new MyClass();
console.log(instance1.options.elementSize); // Returns 10
instance1.options.elementSize = 20;
console.log(instance1.options.elementSize); // Returns 20
var instance2 = new MyClass({
elementSize: 15
});
console.log(instance2.options.elementSize); // Returns 15
In your example, the classes are initiated as Array variables, so you can change the options like so:
rpbArrayB.rpbB1.options.elementSize = 20
Note that this might not always have the desired effect though. If the class takes the options on initialization and doesn't use them anymore afterwards, changing the options will have no effect on an initialized class. In that case you would have to re-initialize the class.

Leaflet: Pass an extra argument to L.geoJson options

I'm working on choropleth maps using Leaflet framework. I'd like to have several separate layers for several years, so i' ve written this code (note that only names of 'style2002' and 'style2010' should be passed, without any arguments):
population2002 = L.geoJson(regionData, {
style: style2002
});
population2010 = L.geoJson(regionData, {
style: style2010
});
, there "style" functions which are colouring my vector polygons depening on their attributes (which names are prefix 'Pop_' plus year) are:
function style2002(feature)
{
return {
fillColor: getColor(feature.properties.Pop_2002),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '',
fillOpacity: 0.7
};
}
function style2010(feature)
{
return {
fillColor: getColor(feature.properties.Pop_2010),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '',
fillOpacity: 0.7
};
};
As you can guess, i want to use one "style" function instead of separate functions for each year i need. Something like:
function styleByYear(feature, year)
{
var property = 'feature.properties.Pop_';
property += year;
return {
fillColor: getColor(property),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '',
fillOpacity: 0.7
};
}
But how to pass the second argument to style function? In L.geoJson constructor i write only the name of function, without any arguments, as you can see from the first piece of code!
What should i do?
And one more question: how the first argument ('feature') is passed into layer constructor..?
What if you create a global variable:
var property = 'Pop_' + year
and the edit your function to the following(You should use brackets instead of dot notation):
function styleByYear(feature)
{
return {
fillColor: getColor(feature['properties'][property]),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '',
fillOpacity: 0.7
};
}
I have done something similar to what you're asking based on choropleth tutorial like you. I have multiple buttons that changes map style for different dates.
You could try what is in the Leaflet tutorial on GeoJSON. Look for the second code section in the "Options" section. You would just add the normal styling first (i.e. the stuff that is the same for both years). Example taken from that site adding your particular code:
geojsonlayer = L.geoJson(regionData, {
style: function(feature) {
var finalStyleObject = normalStyling(feature); //return the normal style object
switch (feature.properties) { //switch through the various years
case 'Pop_2002': {finalStyleObject.fillColor: "#ff0000"};
case 'Pop_2010': {finalStyleObject.fillColor: "#0000ff"};
}
return finalStyleObject;
}
});
function normalStyling(feature){
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '',
fillOpacity: 0.7
};
}

Categories

Resources