Angular 6 with Openlayers drawLine - angular6

I want to draw a routing line from Land of Canaan to Waipu but After I compile the line become like this,
What I expect is like this,
My code:
routing.forEach((obj, index) => {
const line_point = [];
obj.waypoints.forEach((pos, i) => {
const lng = Number(pos.lon);
const lat = Number(pos.lat);
line_point.push(ol.proj.fromLonLat([lng, lat]));
});
const routeLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature({
geometry: new ol.geom.LineString(line_point, 'XY'),
name: 'Line'
})]
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#bc0000',
width: 2
})
})
});
routeLayer.setZIndex(55);
this.mapLayer.push(routeLayer);
this.map.addLayer(routeLayer);
});
May I know what happened to this and how to solve it?

One of your LineString ist crossing the antimeridian (180° W/E). A solution is to split the LineString at the antimeridian.

Your algorithm is have issues. You have to consider split the line in as many chunks as be needed. As you did not provided the code, I am able only to include cases in conceptual way.
Your array variable could be an array of arrays with all line chunks needed to draw.
line_point
Includes a draw with border cases:
Line a-b is similar to your case with two chunks.
Line c-d is other case with two chunks.
Line e-f is an complex case where there is three chunks.
The dotten light green line represent the union between the chunks

Related

Superset & DECK.GL -- cannot display shaded polygons

I want to visualize Zip3 polygons, shaded by the population. I have GeoJSON formatted as text strings in a Snowflake table, and am able to visualize them using the "Deck.GL GEOJSON" map type, but not "Deck.GL Polygon", which is what I need.
I have tested the GeoJSON with geojson.io and they are valid.
This is a "Deck.GL Polygon" type and does not work (showing up blank, but with the Legend correctly displaying):
This is a "Deck.GL GEOJSON" type and which DOES work (but does not allow me to color it by population):
Any ideas how to shade these polygons in Superset?
Why do you need PolygonLayer instead of GeoJsonLayer? At the end GeoJsonLayer renders a SolidPolygonLayer
So, GeoJsonLayer = SolidPolygonLayer
One of the differences between rendering a GeoJsonLayer or SolidPolygonLayer is that, if your data is already a geojson format, you don't need to specify an accessor to tell deck.gl where your data coordinates are located (because internally interprets where those are => feature => geometry => coordinates)
I would go using a GeoJsonLayer, and then, for styling polygons, you will need to use getFillColor accessor like:
new GeoJsonLayer({
...,
getFillColor: ({ properties }) => {
if (properties.population > 1_000_000) {
return [255, 0, 0]
}
return [0, 255, 0]
}
})

How to add legend for a bar chart with different colors in dc.js?

Below is the code snippet for a barchart with colored bars:
var Dim2 = ndx.dimension(function(d){return [d.SNo, d.something ]});
var Group2 = Dim2.group().reduceSum(function(d){ return d.someId; });
var someColors = d3.scale.ordinal().domain(["a1","a2","a3","a4","a5","a6","a7","a8"])
.range(["#2980B9","#00FFFF","#008000","#FFC300","#FF5733","#D1AEF1","#C0C0C0","#000000"]);
barChart2
.height(250)
.width(1000)
.brushOn(false)
.mouseZoomable(true)
.x(d3.scale.linear().domain([600,800]))
.elasticY(false)
.dimension(Dim2)
.group(Group2)
.keyAccessor(function(d){ return d.key[0]; })
.valueAccessor(function(d){return d.value; })
.colors(someColors)
.colorAccessor(function(d){return d.key[1]; });
How do I add a legend to this chart?
Using composite keys in crossfilter is really tricky, and I don't recommend it unless you really need it.
Crossfilter only understands scalars, so even though you can produce dimension and group keys which are arrays, and retrieve them correctly, crossfilter is going to coerce those arrays to strings, and that can cause trouble.
Here, what is happening is that Group2.all() iterates over your data in string order, so you get keys in the order
[1, "a1"], [10, "a3"], [11, "a4"], [12, "a5"], [2, "a3"], ...
Without changing the shape of your data, one way around this is to sort the data in your legendables function:
barChart2.legendables = function() {
return Group2.all().sort((a,b) => a.key[0] - b.key[0])
.map(function(kv) {
return {
chart: barChart2,
name: kv.key[1],
color: barChart2.colors()(kv.key[1]) }; }) };
An unrelated problem is that dc.js takes the X domain very literally, so even though [1,12] contains all the values, the last bar was not shown because the right side ends right at 12 and the bar is drawn between 12 and 13.
So:
.x(d3.scale.linear().domain([1,13]))
Now the legend matches the data!
Fork of your fiddle (also with dc.css).
EDIT: Of course, you want the legend items unique, too. You can define uniq like this:
function uniq(a, kf) {
var seen = [];
return a.filter(x => seen[kf(x)] ? false : (seen[kf(x)] = true));
}
Adding a step to legendables:
barChart2.legendables = function() {
var vals = uniq(Group2.all(), kv => kv.key[1]),
sorted = vals.sort((a,b) => a.key[1] > b.key[1] ? 1 : -1);
// or in X order: sorted = vals.sort((a,b) => a.key[0] - b.key[0]);
return sorted.map(function(kv) {
return {
chart: barChart2,
name: kv.key[1],
color: barChart2.colors()(kv.key[1]) }; }) };
Note that we're sorting by the string value of d.something which lands in key[1]. As shown in the comment, sorting by x order (d.SNo, key[0]) is possible too. I wouldn't recommend sorting by y since that's a reduceSum.
Result, sorted and uniq'd:
New fiddle.

D3 Line Generator Handling Multiple Arrays

I have 3 arrays within a JSON file of the following structure:
I am trying to parse a JSON file of coordinate data into something that can be read by D3 path/line generators. I first had to find a way to ensure the values were actual numbers and not strings. A full discussion can be found here:
D3/JS mapping a JSON data callback
That discussion prompted me to not only consider formatting the JSON data via .map() to numbers, but also consider a nested/zipped format that the line generator can make sense of. That is really the target I've been after all along. As depicted above, My JSON has 3 arrays, xs, ys and id. id only governs color, and takes 1 of 3 values (0,1,2). I was recommended this approach:
var obj = raw_json[0];
var data = obj.id.map((id, i) => [+id, +obj.xs[i], +obj.ys[i]]);
My line generator function is:
var valueLine = d3.svg.line()
.x(function(d) {return xScale(d.xs);})
.y(function(d) {return yScale(d.ys)});
However I am getting tens of thousands of errors, and unfortunately I do not have that much experience with parsing related issues and I am not sure how to proceed.
Full block & JSON here.
Glad to see you took my advice on restructuring your data as we are moving in the right direction. I suggested that you should convert your three separate arrays into one array of individual arrays per point to make the use of the line generator more easy and to eliminate the need for cross-array reads to collect data for the points.
This time, though, you are not accessing your values correctly. By using function(d) { return xScale(d.xs); } you are assuming that your points were represented by objects having properties xs and ys. My suggested approach however got rid of these properties by storing the information into arrays. There are basically two ways around this:
Adjust you path generator's .x() and .y() callbacks while keeping your data structure.
var obj = raw_json[0];
var data = obj.id.map((id, i) => [+id, +obj.xs[i], +obj.ys[i]]);
// Remember, that d is a point's array [id, x, y]
var valueLine = d3.svg.line()
.x(function(d) { return xScale(d[1]); })
.y(function(d) { return yScale(d[2]); });
If you prefer to store your points' data in objects instead, another solution would be to adjust how your data is built.
// Structure data into an array of objects {id, x, y}
var obj = raw_json[0];
var data = obj.id.map((id, i) => ({
id: +id,
x: +obj.xs[i],
y: +obj.ys[i]
}));
// Keep your code as d now has properties x and y.
var valueLine = d3.svg.line()
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); });
I think you aren't modeling correctly the data to use to use with data(data).enter() and/or d3.svg.line(). As you defined your valueLine function it expects an array of objects with xs and ys properties and you are feeding it with an array of arrays.
Try it out manually to see how it works
valueLine([{xs: 1, ys: 1}, {xs: 3, ys: 5}, {xs: 12, ys: 21}])
and see the generated svg path:
"M100,400L300,-400L1200,-3600"
So maybe you can change how you are preparing your data for something like :
var data = obj.id.map((id,i) => ({id: +id, xs:+obj.xs[i], ys: +obj.ys[i]}));

How to split Map into two maps based on a condition

I'm relatively new to React using Immutable.js.
Let's say I have a (Ordered) Map of 30 items, in which some have the color green and some the color red.
Now I want to split this Map into two Maps, one containing the first five green items and the other containing the rest (rest of the green items and red items).
If I had an array, I would just define two result-arrays, iterate through my src-array and put the items in their according result-array. If I did that with immutable.js, I would need to create a new Map every time something changes. Is that still the way to go, or are there faster / more elegant ways to achieve that?
Thanks in advance!
If I get the question right, most elegant way is to use Map.filter
const { Map } = Immutable;
const sourceMap = new Map({
key1: { color: "red" },
key2: { color: "green" },
});
const filterMap = c => sourceMap.filter(({ color }) => color === c);
const greenMap = filterMap("green");
const redMap = filterMap("red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>

How to display yearly values on xAxis in Highcharts

I guess this is somewhat of a stupid question. But I am struggling since quite a while with this, not finding what the right way of data formatting is for my data.
I have yearly data like this, which I want to have displayed as such - 2001, 2002, 2003, ...:
time,lat,lon,Npp_1km
Date.UTC(2001/1/1),15,-90,1.266112766
Date.UTC(2002/1/1),15,-90,1.166646809
Date.UTC(2003/1/1),15,-90,1.020591489
Date.UTC(2004/1/1),15,-90,1.016010638
Date.UTC(2005/12/31),15,-90,1.08053617
Date.UTC(2006/12/31),15,-90,1.181195745
and my Highcharts code which looks like this:
xAxis: {
labels: {
style: {
color: "#666666"
},
x: 0
},
gridLineWidth: 1,
gridLineDashStyle: 'Dot',
tickWidth: 0,
type: 'datetime'
},
But the xAxis doesn't display the years but instead some "00:00:00.001".
I have tried many different formats for the timestamp - "2001-1-1", "2001/1/1", "1/1/2001", "1-1-2001", "Date.UTC(2001/1/1)". I have changed the "dateTimeLabelFormats" as well. But all in vain. It doesn't spit out "2001 - 2002 - 2003 - 2004".
Here is a fiddle.
What is the right way to achieve this? Thanks for any hints!
You had problems with parsing your data. All of your x values was not correct - that is the reason of your issue. You need to parse it a little bit different if you want to get the correct data for your chart:
$.get('data.csv', function(data) {
var temp = []
// Split the lines
var lines = data.split('\n');
// For each line, split the record into seperate attributes
$.each(lines, function(lineNo, line) {
var items = line.split(',');
if (lineNo !== 0) {
items[0] = items[0].substring(items[0].indexOf('(') + 1, items[0].indexOf(')'));
var x = new Date(items[0]),
y = parseFloat(items[3]);
if (!isNaN(y)) {
x = x.getTime();
options.series[0].data.push([x, y]);
}
}
});
Here you can see an example how it can work:
http://jsfiddle.net/pcpq6mtr/4/
Regards,
A simple solution can be put categories in xAxis if the time is fixed.
xAxis {
categories:[2001,2002,2003,2004,2005,2006]
}
If the time is not fixed. categories need to be calculated dynamically.