Deck.GL, Creating a Polygon layer with a rectangle that has a slope - mapbox

Question
I've been trying multiple ways to create a rectangle that has a slope, tried using the GeoJsonLayer and PolygonLayer to accomplish this. I can't seem to find a way to create the shape and have it extend all the way to the ground on all sides. I use the Z index on the coordinates to tell it what altitude it should put the vertex at.
To give a clear picture of what I'm trying to do, I basically want to have a rectangle that can be sloped on a side but still have it extend until the ground instead of floating in the air.
const data = [
{
contour: [[-122.4, 37.75, 2000], [-122.4, 37.8, 2000], [-122.5, 37.8], [-122.5, 37.75], [-122.4, 37.75]],
}
];
const overlay = new MapboxOverlay({
layers: [
new PolygonLayer({
id: 'polygon-layer',
data: data,
pickable: true,
stroked: true,
filled: true,
wireframe: true,
extruded: true,
lineWidthMinPixels: 5,
getPolygon: d => d.contour,
getFillColor: [255, 0, 0, 100],
getLineColor: [80, 80, 80],
getLineWidth: 1,
transitions: { getElevation: 600 }
})
]
});

Related

Mapbox GL JS interactivity on a Warehouse Floorplan as the base map plausible?

I am trying to figure out if Mapbox GL JS would be applicable or fit for my use case:
My base map example has to be made of several components of a warehouse instead of Geospatial map
I would like to display a clustering layer representing, for example, the number of products stored at a particular shelf/section in the warehouse.
Each box/product in the warehouse would be represented as a pinpoint and while zooming out, collection of products/boxes would be represented as a cluster.
With that said, I'm aware 2) and 3) would be supported in case of a geospatial map but my concern is aimed at an customized non-geospatial map, if applicable.
Geospatial or not, it all boils down to coordinates. Mapbox GL JS expects geographic coordinates, so you just need to carve out a portion of the coordinate range (-180 thru 180 on the x axis, -90 to 90 on the y axis) that will meet your needs, and make sure you have good coordinates for the shelves or wherever you need to visualize clusters.
Here's a codepen that shows a simple mapbox style with only a background and a rectangle. No streets, no rivers, no labels...
const map = (window.map = new mapboxgl.Map({
container: "map", // container ID
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: {
version: 0,
name: "Foo",
sources: {
"building-outline": {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
[
[0, 0],
[60, 0],
[60, 30],
[0, 30],
[0, 0]
]
]
}
}
}
},
layers: [
{
id: "background",
type: "background",
paint: {
"background-color": "steelblue"
}
},
{
id: "building-fill",
type: "fill",
source: "building-outline",
paint: {
"fill-color": "#ccc"
}
},
{
id: "building-line",
type: "line",
source: "building-outline"
}
]
}, // style URL
center: [30,20], // starting position [lng, lat]
zoom: 2 // starting zoom
}));
https://codepen.io/chriswhong/pen/XWqpPXN
You can also build your own style in Mapbox Studio.

How to define starting grid position on Leaflet's TileLayer?

My app needs to show a map within a box defined by
const corner1 = L.latLng(5.21244812011719, -96.5979537963867);
const corner2 = L.latLng(34.086555480957, -55.4220504760742);
const map = L.map(el,
{
crs: L.CRS.EPSG4326,
center: [19.6875, -76.201171875],
zoom: 3.5,
maxBounds: new L.latLngBounds(corner1, corner2),
});
L.tileLayer.wms("http://localhost:8080/wms?", {
layers: 'xxx',
tileSize: 700,
transparent: true,
maxBounds: new L.latLngBounds(corner1, corner2),
bounds: new L.latLngBounds(corner1, corner2)
}).addTo(map)
The thing is that the layer is requesting the tiles starting outside the borders defined (for example, this request was made http://localhost:8080/wms?&service=WMS&request=GetMap&layers=Mano%3AT22&styles=&format=image%2Fjpeg&transparent=true&version=1.1.1&maxBounds=%5Bobject%20Object%5D&time=2018-05-02T00%3A00%3A00.000Z&width=700&height=700&srs=EPSG%3A4326&bbox=-87.71484375,28.4765625,-56.953125,59.23828125 the bbox was -87.71484375, 28.4765625, -56.953125, 59.23828125, this contains the corners defined by me but is not optimal as it is requesting a map area that is not going to be seen on my app)
I need that leaflet request tiles that do not exceed the corners defined. How can I archieve that? Thanks in advance

Leaflet + Turf strange squareGrid behaviour

After a week of tests, and researches I've decided to "give up" and ask you guys for some help.
What I'm trying to accomplish is fairly easy.
Take the world map and split it in 4 quadrants (done)
Take each quadrant, and using turf calculate how many squares of N units are contained.
Everything works fine with the 2 first quadrants: A (red), B (green)
In fact, if I then try to fill the first two quadrants with squares using turf the result is correct:
The problem is that when trying to replicate the same logic on the squares below, turf returns 0 squares...
The code used to create the 4 quadrants with Leaflet is the following:
const quadrantA = L.rectangle(L.latLngBounds(L.latLng(90, -180), L.latLng(0, 0)), { weight: 1, fillColor: 'red', color: 'red' });
const quadrantB = L.rectangle(L.latLngBounds(L.latLng(90, 0), L.latLng(0, +180)), { weight: 1, fillColor: 'green', color: 'green' });
const quadrantC = L.rectangle(L.latLngBounds(L.latLng(0, -180), L.latLng(-90, 0)), { weight: 1, fillColor: 'blue', color: 'blue' });
const quadrantD = L.rectangle(L.latLngBounds(L.latLng(0, 0), L.latLng(-90, 180)), { weight: 1, fillColor: 'yellow', color: 'yellow' });
quadrantA.addTo(this.map);
quadrantB.addTo(this.map);
quadrantC.addTo(this.map);
quadrantD.addTo(this.map);
Meanwhile the code used to calculate the squares in each quadrant with turf is the following:
const QGrid_A = turf.squareGrid(turf.bbox(quadrantA.toGeoJSON()), 500, { units: 'kilometers' });
const QGrid_B = turf.squareGrid(turf.bbox(quadrantB.toGeoJSON()), 500, { units: 'kilometers' });
const QGrid_C = turf.squareGrid(turf.bbox(quadrantC.toGeoJSON()), 500, { units: 'kilometers' });
const QGrid_D = turf.squareGrid(turf.bbox(quadrantD.toGeoJSON()), 500, { units: 'kilometers' });
Problem is, that the "second round" of calculations returns always 0 features for the quadrants C and D.
QGrid_A features: 800
QGrid_B features: 800
QGrid_C features: 0
QGrid_D features: 0
I've also read about that Leaflet reverses the standard GeoJSON coordinates positions, by using [LAT,LON] instead of [LON,LAT], so I've also tried to reverse the result of the Leaflet generated GeoJSONs by doing a reverse on the coordinates array, but still nothing.
I wonder where am I wrong here? Is it a problem of "looped" coordinates? Is it a problem due to a falsy conversion between Leaflet and Turf? Is it me dumb? Please help me guys.
My solution
At the end of the day, I've adopted another strategy. Pretty simple tbh.
I've created a polygon which is the "area to map". This polygon then is split in several sub-squares polygons. Each square then can be used as an individual "tile".
Using #turf/square-grid and #turf/bbox was to achieve this was pretty easy,
the code for this is all incapsulated in 2 functions:
export interface ISplitAreaInSubareasConf {
squareCellSide?: number;
units?: `meters` | `kilometers`;
}
private splitAreaToMapInSubAreas(areaToMap: Polygon, opts?: ISplitAreaInSubareasConf): BBox[] {
const units = opts && opts.units ? opts.units : this.SQUARE_UNIT;
const side = opts && opts.squareCellSide ? opts.squareCellSide : this.SQUARE_CELL_SIDE_IN_KM;
const grid = turfSquareGrid.default(this.getAreaToMapBBox(areaToMap), side, {units, mask: areaToMap});
return grid.features.map(feat => this.getAreaToMapBBox(feat.geometry));
}
private getAreaToMapBBox(areaToMap: Polygon) {
return bbox.default(areaToMap);
}

How to draw a chart with nonlinear x-axis (logarithmic scale)?

I am trying to draw a Critical Power Chart like this:
The data I get is linear. One value for every second from 1 up to 18000.
I have no clue how to teach flot to draw an non-linear x-axis.
I tried to set custom ticks, but this seems to just have impact to the labels, not the line.
The x axis ticks will always be the same and don't need to be calculated:
[1s,5s,15s,30s,1m,2m,3m,5m,10m,20m30m,1h,2h,3h,5h]
Playground including tons of data: https://jsfiddle.net/ogeo2ygx/6/
Code:
$.plot($("#cpChart"), [{data: data,label: "Critical Power", labelBoxBorderColor: 0, color: '#cbcbcb',yaxis:1,lines: { show: true, fill: true } }], {
xaxes: [{
//here should be some Magic to Draw an nice Critical Power Chart
tickFormatter: (t, v) => {
return t + "s";
}
}],
yaxes: [{
alignTicksWithAxis: 1,
position: "left",
tickFormatter: (t, v) => {
return t.toFixed(0) + " Watt"
}
}],
legend: {
position: 'sw',
labelBoxBorderColor: 0
},
colors: ["#1ab394"],
grid: {
color: "#999999",
clickable: true,
tickColor: "#D4D4D4",
borderWidth: 0,
hoverable: true
}
});
You can achieve that (which is called logarithmic scale) with two steps:
Transform the x-axis values using the Math.log function (with a +1 because the logarithm of zero is -infinity).
Define a custom ticks array with your ticks.
See the documentation for more information.
Relevant code:
xaxes: [{
ticks: [[1, '1s'],[5, '5s'], [15, '15s'],[30, '30s'],[60, '1m'],[120, '2m'],[180, '3m'], [300, '5m'], [600, '10m'], [1200, '20m'], [1800, '30m'],[3600, '1h'], [7200, '2h'], [10800, '3h'], [18000, '5h']],
transform: (x) => { return Math.log(1 + x); },
inverseTransform: (x) => { return Math.exp(x) - 1; }
}],
Updated fiddle: https://jsfiddle.net/ogeo2ygx/8/

Embed bubble charts on a web site

I'm looking for a way to create what come to know to be called a "bubble chart" for a website I'm building. It needs to be compatible with IE7 and above, and of course all the good browsers like Firefox, Chrome and Safari. And no flash since this thing will need to run on iOS.
The chart needs to look like this, http://www.flickr.com/photos/jgrahamthomas/5591441300/
I've browse online and tried a few things, including:
Google Scatter Charts. This doesn't work as it seems Google Charts limits the size of a point to something smaller than I need. And Venn Diagrams are limited to three circles.
Protovis Dots. Great library, but isn't compatible with IE8.
Raphael Javascript. This one might be my best bet, but there's no explicit support for bubble charts.
Thanks for your help.
It looks like Raphael javascript is the way to go. It's compatible with IE6. I found a great tutorial at http://net.tutsplus.com/tutorials/javascript-ajax/an-introduction-to-the-raphael-js-library/ and am able to get the example working on my rails site with this code:
# window.onload = function() {
# var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
# var circle = paper.circle(100, 100, 80);
# for(var i = 0; i < 5; i+=1) {
# var multiplier = i*5;
# paper.circle(250 + (2*multiplier), 100 + multiplier, 50 - multiplier)
# }
# var rectangle = paper.rect(200, 200, 250, 100);
# var ellipse = paper.ellipse(200, 400, 100, 50);
# }
You can give Protovis a chance, the library looks good for your needs: http://vis.stanford.edu/protovis/ex/
Another charting library is Highcharts, but I haven't tried it yet: http://www.highcharts.com/
Have you had a look at flot?
It's a plotting library for jQuery. While it technically doesn't have any "native" support for bubble charts it is possible to create bubble charts with it by using a few tricks, the simplest one probably being to simply put each point in its own data series (thus allowing you to control the radius of each individual point.
By defining your points similar to this you'll be able to create a bubble chart:
var dataSet = [{
color:"rgba(0,0,0,0)", // Set the color so it's transparent
shadowSize:0, // No drop shadow effect
data: [[0,1],], // Coordinates of the point, normally you'd have several
// points listed here...
points: {
show:true,
fill:true,
radius: 2, // Here we set the radius of the point (or rather, all points
// in the data series which in this case is just one)
fillColor: "rgba(255,140,0,1)", // Bright orange :D
}
},
/* Insert more points here */
];
There is a bubble chart available for flot here
Note that you need to scale your bubbles size yourself if you don't want them to coverup the graph. Documentation is here.
To use it, add the following at the beggining of your html page:
and call it from a json result or any data object like in this sample:
$.getJSON('myQuery.py?'+params, function(oJson) {
// ... Some validation here to see if the query worked well ...
$.plot('#myContainer',
// ---------- Series ----------
[{
label: 'Line Sample',
data: oJson.lineData,
color: 'rgba(192, 16, 16, .2)',
lines: { show: true },
points: { show: false }
},{
label: 'Bubble Sample',
data: oJson.bubbleData, // arrays of [x,y,size]
color: 'rgba(80, 224, 80, .5)',
lines: { show: false },
points: { show: false },
},{
label: 'Points sample',
data: oJson.pointsData,
color: 'rgba(255, 255, 0, 1)',
lines: { show: false },
points: { show: true, fillColor: 'rgba(255, 255, 0, .8)' }
},{
...other series
}],
// ---------- Options ----------
{ legend: {
show: true,
labelBoxBorderColor: 'rgba(32, 32, 32, .2)',
noColumns: 6,
position: "se",
backgroundColor: 'rgba(224, 224, 224, .2)',
backgroundOpacity: .2,
sorted: false
},
series: {
bubbles: { active: true, show: true, fill: true, linewidth: 2 }
},
grid: { hoverable: true, clickable: true } },
xaxis: { tickLength: 0 }
}); // End of plot call
// ...
}); // End of getJSON call
I tried to do the same thing with jqPlot which has some advantages but doesn't work with bubbles and other kind of series on the same graph. Also Flot does a better job to synchronise common axis scale with many series. Highchart does a really good job here (mixing bubble chart with other kind of series) but isn't free for us (government context).