Have successfully imported polygons in OpenLayers along with popup of pertinent data. Need guidance on assigning fill colors from parameters passed via ajax.
your textHoping to assign fill color based on setting parameter in json file. Currently using:
var polyStyle = new ol.style.Style({
fill: new ol.style.Fill({
color: [12,240,60]
}),
stroke: new ol.style.Stroke({
color: [0,0,0], width: 1
})
});
to load the following:
const layer = new ol.layer.Vector({
source: new ol.source.Vector({
features:features,
projection: 'EPSG: 3857'
}),
style: polyStyle
});
I next tried the following as a test based on the "settings feature the file:
// Polygons style
var setfcolor = function(features) {
console.log(features);
var fcolor;
if (feature.get("setting")=='Carbonate'){
fcolor = "blue";
} else if (feature.get("setting")=='Clastic: continental'){
fcolor = "yellow";
} else if (feature.get("setting")=='Extrusive: mafic'){
fcolor = "brown";
}
};
But it fails and reverts to all black.
Snippet of json file is:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-45.499757432,
60.988125868
],
[
-45.49967049,
60.988157751
],
[
-45.497458466,
60.989470026
],
[
-45.487258845,
60.995518876
],
[
-45.483858593,
60.999870372
],
[
-45.483858591,
60.99987019
],
[
-45.465241806,
60.991366687
],
[
-45.450273556,
60.988997409
],
[
-45.422944921,
60.990687369
],
[
-45.42294477,
60.990687194
],
[
-45.419225021,
60.984549241
],
[
-45.412472331,
60.973399399
],
[
-45.502278621,
60.96070259
],
[
-45.525166866,
60.957726342
],
[
-45.544395412,
60.955624111
],
[
-45.572353843,
60.951692596
],
[
-45.655768925,
60.94244974
],
[
-45.670854236,
60.94123391
],
[
-45.693899808,
60.940200373
],
[
-45.664305174,
60.947778021
],
[
-45.659448977,
60.949020163
],
[
-45.648191047,
60.951923402
],
[
-45.636669092,
60.954825483
],
[
-45.565410441,
60.967827923
],
[
-45.523123774,
60.979977384
],
[
-45.517219284,
60.981999
],
[
-45.517218946,
60.981999115
],
[
-45.5059008,
60.985872696
],
[
-45.499757432,
60.988125868
]
]
]
},
"properties": {
"setting_ty": "Supracrustal",
"setting": "Sedimentary and/or volcanic: undivided",
"lithology": "Basalt, sandstone, conglomerate",
"colour_cmy": "20 40 70 0",
"colour": "247"
}
},
[Polygons and popups working](https://i.stack.imgur.com/TqbV8.jpg)
strong text Got a good lead from Mike user:10118270 and applied it.Replaced the following code
var polyStyle = new ol.style.Style({
fill: new ol.style.Fill({
color: [12,202,50]
}),
stroke: new ol.style.Stroke({
color: [0,0,0], width: 1
})
});
with the following code:
// Polygons style
const fillColors = {
'Slope and deep water': [100,100,100,1],
'Intrusive: syenitic': [240,10,10,1],
'Intrusive: gabbroic': [240,10,10,1],
'Intrusive: anorthositic': [240,10,10,1],
'Intrusive: tonalitic-granodioritic': [240,10,10,1],
'Intrusive: granitic':[240,10,10,1],
'Intrusive: undivided': [230,10,10,1],
'Sedimentary: undivided': [250,250,10,1],
'Clastic: shallow marine': [240,240,20,1],
'Clastic: continental': [255,255,1,1],
'Clastic: deltaic and nearshore': [240,240,20,1],
'Marine sedimentary: undivided': [230,230,10,1],
'Extrusive: mafic': [250,200,10,1],
'Sedimentary and/or volcanic: undivided': [250,120,10,1],
'Carbonate': [10,40,255,1],
'Metamorphic: undivided': [230,10,240,1],
'ice': [250,250,250,1],
};
const style = new ol.style.Style({
fill: new ol.style.Fill(),
stroke: new ol.style.Stroke({
color: [0, 0, 0, 1],
width: 0.5,
}),
});
strong text The end result is shown on the image.
geologic polygon
getting the above error when i run $bucket with $group in mongodb laravel.
input collection:
{
"id": "n54qllhzwdlxqvy",
"season_id": "vl7oqdehzjxr510",
"status_id": 8,
"venue_id": "",
"referee_id": "",
"neutral": 1,
"note": "",
"home_scores": [0, 0, 0, 0, 0, 0, 0],
"away_scores": [1, 0, 0, 0, 0, 0, 0],
"home_position": "",
"away_position": "",
"coverage": {
"mlive": 0,
"lineup": 0
},
"round": {
"stage_id": "ednm9whz7xoryox",
"round_num": 0,
"group_num": 3
},
"updated_at": "2021-05-03 16:53:52",
"competition_id": "gpxwrxlhdgryk0j",
"competition_name": "Chinese U18 Women's National Games",
"home_team_id": "2y8m4zh8xwjql07",
"home_team_name": "Fujian U18 Women ",
"away_team_id": "8yomo4hvxg2q0j6",
"away_team_name": "Shandong U18 Women",
"match_time": "2021-05-03 15:00:00",
"match_tsp": 1620025200,
"created_at": "2021-05-04 14:33:05"
}
$data = DB::connection('mongodb_football')->collection('match_list')->raw(function ($collection) {
return $collection->aggregate([
[
'$bucket' => [
'groupBy' => '$competition_id',
'boundaries' => ["4zp5rzgh3nq82w1","4zp5rzghjjgq82w", "4zp5rzghkzq82w1","4zp5rzghpvnq82w","4zp5rzghx38q82w","4zp5rzghx5q82w1"],
'default' => "Other",
'output' => [
"data" => [
'$push' => [
"season_id" => '$season_id'
]
]
]
]
]
]);
});
output:
need to group all data based on competition_id and need all the data.
Remove $ prefix from groupBy, boundaries, default, and output.
The $bucket 'groupBy' field must be defined as a $-prefixed path or an expression
It says group by field required reference field that should be prefix by $, but you have assigned it in array bracket [].
Try below syntax, i have not tested yet but it would be,
$data = DB::connection('mongodb_football')->collection('match_list')->raw(function ($collection) {
return $collection->aggregate([
[
'$bucket' => [
'groupBy' => '$competition_id',
'boundaries' => ["4zp5rzgh3nq82w1","4zp5rzghjjgq82w", "4zp5rzghkzq82w1","4zp5rzghpvnq82w","4zp5rzghx38q82w","4zp5rzghx5q82w1"],
'default' => "Other",
'output' => [
"data" => [
'$push' => [
"season_id" => '$season_id'
]
]
]
]
]
]);
});
Playground
Solution
$data = DB::connection('mongodb_football')->collection('match_list')->raw(function ($collection) {
return $collection->aggregate([
[
'$bucket' => [
'groupBy' => '$competition_id',
'boundaries' => ["4zp5rzgh3nq82w1","4zp5rzghjjgq82w", "4zp5rzghkzq82w1","4zp5rzghpvnq82w","4zp5rzghx38q82w","4zp5rzghx5q82w1"],
'default' => "Other",
'output' => [
"data" => [
'$push' => [
"season_id" => '$season_id'
]
]
]
]
]
]);
});
I've read and used Mike Bostock's answer to Center a map in D3 given a geoJSON object, which is a generic way to scale to fit one item in a geojson file based on its bounds in D3 version 3. I've also adapted it to use every item in a GeoJson. Key part of that algorithm is:
// Calculate bounding box transforms for entire collection
var b = path.bounds( geojson ),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
// Update the projection, which initially had .translate([0, 0]) .scale(1);
projection
.scale(s)
.translate(t);
Using the V4 D3-geo docs I've crudely adapted it to work in with the new/ammended d3.geoPath() function / object in D3 version 4.0. It seems to work in the demo below (I'm using d3.geoPath().bounds(), not yet tried V4's seemingly new d3.geoBounds()). However, I then get stuck with adapting it to get the bounding box across all layers in a multi-layer topojson file that has been converted using topojson.js (i.e. the bounding box of multiple GeoJSON feature collections). d3.geoPath().bounds() seems to only accept one "layer" and d3.geoBounds() appears even more restricted; to one feature.
I'm also somewhat concerned about performance - all this seems to involve looping over potentially very many shapes in potentially many layers, I feel like maybe there might be a more efficient approach in D3 V4?
Here's a rough demo as a starting point with a very small simple TopoJSON file that should show two islands with a few subregions each (very very simplified versions of Wales and Northern Ireland for a simple demo, each on separate layers). After some trial and error, I've managed to get it to scale and translate the map to centre around the "Wales-like" island, but I can't figure out how to make it centre and scale on all the layers of the TopoJSON.
The standard approach to layered TopoJSON seems to be to turn each layer into what's essentially a seperate GeoJSON, so how do I get the bounds across multiple GeoJSONs while still being able to handle them as separate layers?
//Width and height
var w = 300;
var h = 200;
//Define map projection
var projection = d3.geoEquirectangular()
.translate([0, 0])
.scale(1);
//Define path generator
var path = d3.geoPath()
.projection(projection);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in GeoJSON data
var json = someUKJSON();
for (var key in json.objects) {
if (json.objects.hasOwnProperty(key)) {
// Topojson unpacks one layer at a time
var layer = json.objects[key];
var geojson = topojson.feature( json, layer );
// Calculate bounding box transforms for entire collection
var b = path.bounds(geojson),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
// Update the projection
projection
.scale(s)
.translate(t);
// Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(geojson.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "steelblue");
};
// ...but each iteration will just zoom/centre on the latest
// How do we expand the bounding box with each layer?
}
function someUKJSON(){
return {"type":"Topology","transform":{"scale":[0.0034431267161520807,0.002017902170346754],"translate":[-7.8508544159644345,51.47680014500252]},
"arcs":[[[1366,700],[-216,-155]],[[1150,545],[-121,275],[292,101],[45,-221]],[[1366,700],[23,-449]],[[1389,251],[-77,-96]],[[1312,155],[-75,-18]],[[1237,137],[-62,17]],[[1175,154],[-35,383]],[[1140,537],[10,8]],[[1175,154],[-71,-37]],[[1104,117],[-314,73],[350,347]],[[1237,137],[27,-119]],
[[1264,18],[-35,-18]],[[1229,0],[-125,117]],[[1312,155],[28,-118]],[[1340,37],[-76,-19]],[[1385,12],[-45,25]],[[1389,251],[-4,-239]],[[1385,12],[-156,-12]],[[563,1572],[16,-7]],[[579,1565],[-55,-14]],[[524,1551],[39,21]],[[397,1870],[166,-298]],[[524,1551],[-63,-5]],[[461,1546],[-96,-18]],
[[365,1528],[-109,10]],[[256,1538],[35,290]],[[291,1828],[106,42]],[[574,1342],[-124,192]],[[450,1534],[6,4],[5,8]],[[579,1565],[-5,-223]],[[365,1528],[85,6]],[[574,1342],[-219,-72],[-162,148]],[[193,1418],[63,120]],[[0,1515],[291,313]],[[193,1418],[-193,97]]],
"objects":{"Wales":{"type":"GeometryCollection","geometries":[{"arcs":[[0,1]],"type":"Polygon","id":"Bedr"},{"arcs":[[2,3,4,5,6,7,-1]],"type":"Polygon","id":"Pong"},{"arcs":[[8,9,-7]],"type":"Polygon","id":"Hyda"},{"arcs":[[-6,10,11,12,-9]],"type":"Polygon","id":"Abwg"},
{"arcs":[[13,14,-11,-5]],"type":"Polygon","id":"Cwaf"},{"arcs":[[15,-14,-4,16]],"type":"Polygon","id":"Anan"},{"arcs":[[17,-12,-15,-16]],"type":"Polygon","id":"Cave"}]},"nernIrel":{"type":"GeometryCollection","geometries":[{"arcs":[[18,19,20]],"type":"Polygon","id":"Blft"},
{"arcs":[[21,-21,22,23,24,25,26]],"type":"Polygon","id":"nern"},{"arcs":[[27,28,-23,-20,29]],"type":"Polygon","id":"hern"},{"arcs":[[30,-28,31,32,-25]],"type":"Polygon","id":"sorn"},{"arcs":[[33,-26,-33,34]],"type":"Polygon","id":"wern"}]}}};
};
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
Here's a very simplistic approach. It's the closest any of my attempts at this have come. Leaving it here while hoping someone will come up with something better.
Create a throwaway fake geojson-like object purely for calculating the bounds
Merge the features arrays of each feature into it
Use it to calculate the bounds and adjust the projections once
This feels very clunky though, and I can't find a way to draw one layer at a time with this, I'm resorting to using the throwaway flattened collection to draw the paths.
Also, strangely d3.merge() doesn't seem to work with geojson.features, which is why I'm using Array.concat() instead. Don't understand that one, but this does get it done.
//Width and height
var w = 300;
var h = 200;
//Define map projection
var projection = d3.geoEquirectangular()
.translate([0, 0])
.scale(1);
//Define path generator
var path = d3.geoPath()
.projection(projection);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in GeoJSON data
var json = someUKJSON();
//Create a fake bounds layer
var boundsCollection = {
type: "FeatureCollection",
features: []
}
for (var key in json.objects) {
if (json.objects.hasOwnProperty(key)) {
// Topojson unpacks one layer at a time
var layer = json.objects[key];
var geojson = topojson.feature(json, layer);
boundsCollection.features = boundsCollection.features.concat( geojson.features );
};
}
// Calculate bounding box transforms for entire collection
var b = path.bounds(boundsCollection),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
// Update the projection
projection
.scale(s)
.translate(t);
// Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(boundsCollection.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "steelblue");
function someUKJSON() {
return {
"type": "Topology",
"transform": {
"scale": [0.0034431267161520807, 0.002017902170346754],
"translate": [-7.8508544159644345, 51.47680014500252]
},
"arcs": [
[
[1366, 700],
[-216, -155]
],
[
[1150, 545],
[-121, 275],
[292, 101],
[45, -221]
],
[
[1366, 700],
[23, -449]
],
[
[1389, 251],
[-77, -96]
],
[
[1312, 155],
[-75, -18]
],
[
[1237, 137],
[-62, 17]
],
[
[1175, 154],
[-35, 383]
],
[
[1140, 537],
[10, 8]
],
[
[1175, 154],
[-71, -37]
],
[
[1104, 117],
[-314, 73],
[350, 347]
],
[
[1237, 137],
[27, -119]
],
[
[1264, 18],
[-35, -18]
],
[
[1229, 0],
[-125, 117]
],
[
[1312, 155],
[28, -118]
],
[
[1340, 37],
[-76, -19]
],
[
[1385, 12],
[-45, 25]
],
[
[1389, 251],
[-4, -239]
],
[
[1385, 12],
[-156, -12]
],
[
[563, 1572],
[16, -7]
],
[
[579, 1565],
[-55, -14]
],
[
[524, 1551],
[39, 21]
],
[
[397, 1870],
[166, -298]
],
[
[524, 1551],
[-63, -5]
],
[
[461, 1546],
[-96, -18]
],
[
[365, 1528],
[-109, 10]
],
[
[256, 1538],
[35, 290]
],
[
[291, 1828],
[106, 42]
],
[
[574, 1342],
[-124, 192]
],
[
[450, 1534],
[6, 4],
[5, 8]
],
[
[579, 1565],
[-5, -223]
],
[
[365, 1528],
[85, 6]
],
[
[574, 1342],
[-219, -72],
[-162, 148]
],
[
[193, 1418],
[63, 120]
],
[
[0, 1515],
[291, 313]
],
[
[193, 1418],
[-193, 97]
]
],
"objects": {
"Wales": {
"type": "GeometryCollection",
"geometries": [{
"arcs": [
[0, 1]
],
"type": "Polygon",
"id": "Bedr"
}, {
"arcs": [
[2, 3, 4, 5, 6, 7, -1]
],
"type": "Polygon",
"id": "Pong"
}, {
"arcs": [
[8, 9, -7]
],
"type": "Polygon",
"id": "Hyda"
}, {
"arcs": [
[-6, 10, 11, 12, -9]
],
"type": "Polygon",
"id": "Abwg"
}, {
"arcs": [
[13, 14, -11, -5]
],
"type": "Polygon",
"id": "Cwaf"
}, {
"arcs": [
[15, -14, -4, 16]
],
"type": "Polygon",
"id": "Anan"
}, {
"arcs": [
[17, -12, -15, -16]
],
"type": "Polygon",
"id": "Cave"
}]
},
"nernIrel": {
"type": "GeometryCollection",
"geometries": [{
"arcs": [
[18, 19, 20]
],
"type": "Polygon",
"id": "Blft"
}, {
"arcs": [
[21, -21, 22, 23, 24, 25, 26]
],
"type": "Polygon",
"id": "nern"
}, {
"arcs": [
[27, 28, -23, -20, 29]
],
"type": "Polygon",
"id": "hern"
}, {
"arcs": [
[30, -28, 31, 32, -25]
],
"type": "Polygon",
"id": "sorn"
}, {
"arcs": [
[33, -26, -33, 34]
],
"type": "Polygon",
"id": "wern"
}]
}
}
};
};
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
Is there a way to achieve something as
"dataProvider": <?php json_encode($static_array_1) ?> in amcharts. I've been struggling to figure this out. Could someone please help me/guide me?
I'm fine with anyway of doing this. Either using dataLoader or any other method please.
<script type="text/javascript">
var chart = AmCharts.makeChart("chartdiv", {
"type": "serial",
"theme": "light",
"marginTop":0,
"marginRight": 80,
"dataProvider": <?php json_encode($static_array_1) ?>,
"valueAxes": [{
"axisAlpha": 0,
"position": "left"
}],
"graphs": [{
"id":"g1",
"balloonText": "[[category]]<br><b><span style='font-size:14px;'>[[value]]</span></b>",
"bullet": "round",
"bulletSize": 8,
"lineColor": "#d1655d",
"lineThickness": 2,
"negativeLineColor": "#637bb6",
"type": "smoothedLine",
"valueField": "value"
}],
"chartScrollbar": {
"graph":"g1",
"gridAlpha":0,
"color":"#888888",
"scrollbarHeight":55,
"backgroundAlpha":0,
"selectedBackgroundAlpha":0.1,
"selectedBackgroundColor":"#888888",
"graphFillAlpha":0,
"autoGridCount":true,
"selectedGraphFillAlpha":0,
"graphLineAlpha":0.2,
"graphLineColor":"#c2c2c2",
"selectedGraphLineColor":"#888888",
"selectedGraphLineAlpha":1
},
"chartCursor": {
"categoryBalloonDateFormat": "YYYY",
"cursorAlpha": 0,
"valueLineEnabled":true,
"valueLineBalloonEnabled":true,
"valueLineAlpha":0.5,
"fullWidth":true
},
"dataDateFormat": "YYYY",
"categoryField": "year",
"categoryAxis": {
"minPeriod": "YYYY",
"parseDates": true,
"minorGridAlpha": 0.1,
"minorGridEnabled": true
},
"export": {
"enabled": true
}
});
chart.addListener("rendered", zoomChart);
if(chart.zoomChart){
chart.zoomChart();
}
function zoomChart(){
chart.zoomToIndexes(Math.round(chart.dataProvider.length * 0.4), Math.round(chart.dataProvider.length * 0.55));
}
Sample array I have as output from SQL query -
Array ( [0] => ['DATE','F_L','J_V','L_U','M_C','T_W','T_C'] [1] => ['2015-7',65,0,0,0,20,10] [2] => ['2015-8',32,0,0,0,26,10] )
I think this is best handled on server-side. Here's a PHP function that will convert your data into structure, useful for amCharts:
function consolidateData( $data ) {
// init result array
$result = array();
// get the first row to be used as field names
$cols = array_shift( $data );
// add rows
foreach( $data as $row ) {
$newrow = array();
foreach ( $row as $index => $value ) {
// pad months with zero if necessary
if ( $cols[ $index ] == 'DATE' ) {
$value = preg_replace( '/-([0-9]{1})$/', '-0$1', $value );
}
$newrow[ $cols[ $index ] ] = $value;
}
$result[] = $newrow;
}
return $result;
}
You can then use it like this:
"dataProvider": <?php json_encode( consolidateData( $static_array_1 ) ) ?>,
It will produce a properly-consolidated JSON data and will even convert your months to double-digits because single-digit months are not supported in amCharts:
[ {
"DATE": "2015-07",
"F_L": 65,
"J_V": 0,
"L_U": 0,
"M_C": 0,
"T_W": 20,
"T_C": 10
}, {
"DATE": "2015-08",
"F_L": 32,
"J_V": 0,
"L_U": 0,
"M_C": 0,
"T_W": 26,
"T_C": 10
} ]
Now, you also need to configure your chart properly:
1) Set dataDateFormat to suit your dates:
"dataDateFormat": "YYYY-MM"
2) Add graphs for each value you want to plot, using valueField, such as "F_L", "J_V", etc.
Check out this detail example may helpful
http://ertantoker.blogspot.com/2013/02/use-amcharts-with-prime-faces.html