How to plot GeoJson data in d3.js - javascript

I am trying to display a floorplan to my webapp using d3.js and vue js. The data comes from a .json file and is in a geojson format. I generated some test data from this geojson website. I was thinking I could use the d3.js path function to plot each different object to a svg element. Would this be the correct way to go about doing this? I have looked at this tutorial to make a united states map from geojson data. I was thinking this would be the right way to do it if you inputted different data. However my program spits out random rectangles to the webapp. I think this may be becauseof the projection I am using but Im not sure. I havent used d3.js like this before so its all new to me. I included my code in below. Any help is greatly appreciated and im open to possibly using a different java script library but d3js is preferred.
createFloormap(){
var svg = d3.select("svg")
var width = +svg.attr("width")
var height = +svg.attr("height")
var path = d3.geoPath().projection(d3.geoAlbersUsa().scale(500))
//var path = d3.geoPath()
//var path = d3.geoPath().projection(d3.geoMercator().scale(100))
var x = d3.scaleLinear()
.domain([1, 10])
.rangeRound([600, 860]);
var color = d3.scaleThreshold()
.domain(d3.range(2, 10))
.range(d3.schemeBlues[9]);
var promises = [
d3.json("../static/data.json")
//d3.json("https://raw.githubusercontent.com/adamjanes/udemy-d3/master/08/8.04/data/us-map.json")
]
Promise.all(promises).then(function(data){
ready(data[0]);
})
function ready(us) {
console.log(us)
svg.append("g")
.selectAll("path")
.data(us.features)
//.data(topojson.feature(us, us.objects.states).features)
.enter()
.append("path")
.attr("fill", "grey")
.attr("d", path)
.attr("stroke", "#fff")
.attr("stroke-width", .2)
}
}
},
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-144.140625,
45.583289756006316
],
[
-65.390625,
45.583289756006316
],
[
-65.390625,
69.28725695167886
],
[
-144.140625,
69.28725695167886
],
[
-144.140625,
45.583289756006316
]
]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
9.4921875,
39.36827914916014
],
[
159.609375,
39.36827914916014
],
[
159.609375,
70.02058730174062
],
[
9.4921875,
70.02058730174062
],
[
9.4921875,
39.36827914916014
]
]
]
}
}
]
}

My apologies, I mislead you when commenting on your last question. I read the code and saw an obvious issue - but missed the reference to a floor plan - which for the coordinates given was unlikely to be measured in latitude/longitude pairs. The answer below would be appropriate for a floor plan in lat/long pairs (as would be exported from geojson.io and because projection is less relevant at the building scale) or a geojson floor plan with coordinates in meters/feet.
Geojson in an arbitrary Cartesian coordinate system
You don't have geographic coordinates consisting of latitude/longitude pairs measured in degrees (as I thought when commenting), you have coordinates consisting of x,y values measured in some unit like metres or feet.
To project these corodinates we do not want to use d3.geoSomeProjection because these project latitude/longitude pairs on a sphere to a 2d plane. Nor do we want to use a null projection (the default projection for d3.geoPath) because that treats geojson coordinates as pixel coordinates (we can use a null projection when the coordinates in the geojson have been already been converted to pixel values - we know we don't want a null projection here because we have negative values).
Instead we can use d3.geoIdentity (the geo prefix indicates it is just part of the geo module of D3 but it doesn't require geographic coordinates). This "projection" allows us to apply some projection methods to the data, namely .center() or .scale(). D3 also has two convenience methods that set both simultaneously: fitExtent and fitSize which stretch and translate specified geojson to given dimensions:
var projection = d3.geoIdentity().fitSize([width,height],geoJsonObject)
var projection = d3.geoIdentity().fitExtent([[left,top],[right,bottom]],geoJsonObject)
So, with your data we get:
var data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-144.140625,
45.583289756006316
],
[
-65.390625,
45.583289756006316
],
[
-65.390625,
69.28725695167886
],
[
-144.140625,
69.28725695167886
],
[
-144.140625,
45.583289756006316
]
]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
9.4921875,
39.36827914916014
],
[
159.609375,
39.36827914916014
],
[
159.609375,
70.02058730174062
],
[
9.4921875,
70.02058730174062
],
[
9.4921875,
39.36827914916014
]
]
]
}
}
]
}
var width = 500;
var height = 300;
var svg = d3.select("svg")
.attr("width",width)
.attr("height",height);
var projection = d3.geoIdentity().fitSize([width,height],data)
var path = d3.geoPath(projection);
svg.selectAll("path")
.data(data.features)
.enter()
.append("path")
.attr("d",path);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
One thing to note is that SVG coordinates space, to which d3.geoIdentity is treating coordinates as being in, has the opposite convention as might be expected: y=0 is at the top of the SVG with y values increasing as one moves down. If your coordinates appear to be upside down, then you can use d3.geoIdenity().fitSize(...).reflectY(true)

Related

Google Maps - addGeoJson is not working for my file

addGeoJson is not working in google map for my file
please check below code that I am using in javascript
//create the map
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 6,
center: {lat:49.79, lng: -8.82}
});
// Load GeoJSON.
var promise = $.getJSON("Sensitive_Areas_Nitrates_Rivers.json"); //same as map.data.loadGeoJson();
promise.then(function(data){
cachedGeoJson = data; //save the geojson in case we want to update its values
console.log(cachedGeoJson);
map.data.addGeoJson(cachedGeoJson,{idPropertyName:"id"});
});
I have downloaded this file from here
you can check my JSON file
Sensitive_Areas_Nitrates_Rivers.json
also, you can check this link with polygon
I have used below JSON format so you can check it
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:27700"
}
},
"features": [
{
"type": "Feature",
"id": 1,
"geometry": {
"type": "MultiLineString",
"coordinates": [
[
[
500051.6875,
224280.03130000085
],
[
500047.2812999999,
224277.6875
],
[
499977.5937999999,
224242.625
],
[
499976.6875,
224242.21880000085
]
]
]
},
"properties": {
"OBJECTID": 8,
"type_of_sa": "SA_N",
"datedesign": 1025136000000,
"name": "Rivers Itchen",
"length_km": 12,
"uwwtd_code": "UKENRI134",
"shape_Length": 12172.080443901654
}
}
]
}
[500051.6875, 224280.03130000085] - [X, Y] coordinates may be in EPSG: 27700 to EPSG:4326, Now we need to display these coordinates on google map, Is there any solution for this?
Since Google Maps expects GeoJSON to be in EPSG:4326, Sensitive_Areas_Nitrates_Rivers.json needs to be reprojected. QGIS, for instance, could be utilized for that matter (refer docs for a details)
Reprojected Sensitive_Areas_Nitrates_Rivers.json layer will be displayed like this:
You are getting coordinates in metres. For displaying in google map you need to convert it into [Lng, Lat].
For converting metres to [Lng, Lat] you need to change the projection from EPSG: 27700 to 4326
then only you are able to get this geojson in [Lng, Lat]
Tool you can use: QGIS Desktop 3.4.14
Link: https://qgis.org/en/site/forusers/download.html
After convert you need to export this file as feature.

Maximum inscribed circle in a polygon

I need to draw a maximum inscribed circle in a polygon. I found a library - https://github.com/PieceMaker/max-inscribed-circle - after little of googling. I have to do something wrong as my interpretation returns wrong result ( the circle should be more on right and radius looks strange to me ):
var coords = [
[49.0138, 15],
[49.0138, 15.0167],
[49.0153, 15.0167]
];
var polygon = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [coords]
},
"properties": {
"id": 1
}
};
console.log(maxInscribedCircle(polygon, 7));
returns
{
geometry: {
coordinates: [49.0143, 15.011133333333333],
type: "Point"
},
properties: {
radius: 0.0004823742421792941,
units: "degrees"
}
}
I tried to switch [lat, lon] order, but I get same results.
The question Largest circle inside a non-convex polygon doesn't solve this issue as it describes different algorithm - it doesn't use https://github.com/PieceMaker/max-inscribed-circle library.
Any idea, why position is wrong? How to properly interpret radius - how can "degrees" be length units?

How to display (antimeridian) vector tiles generated by geojson-vt in leaflet using L.CRS.Simple?

I have a GeoJSON simple data that i need to display on a leaflet map using L.CRS.Simple crs, because is antimeridian data, and sometimes, coordinates can be [450,389] (more than 180)
This is the very simple GeoJSON:
{
"type": "FeatureCollection",
"name": "entities",
"features": [
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbPolyline",
"EntityHandle": "1F9",
"style": "PEN(c:#FF0000)"
},
"geometry": {
"type": "LineString",
"coordinates": [
[
0,
0
],
[
0,
150
],
[
150,
150
],
[
150,
0
],
[
0,
0
]
]
}
}
]
}
Using geojson-vt, (demo page) i'm getting this rectangle:
I made some modifications to geojson-vt lib:
Projection functions:
function projectX(x, simple, projectionFactor) {
return x / 256 + 1;
}
function projectY(y, simple, projectionFactor) {
return - y / 256 + 0.5;
}
I added to GeoJSONVT.prototype.getTile function this line:
y = y + (1 << (z - 1)); // xy map
And the result is (markers are placed on [0,0],[150,0],[150,150],[0,150]):
Any suggestion? Why i'm losing tiles here?
I recommend you read this: https://macwright.org/2016/09/26/the-180th-meridian.html
Quoting the GeoJSON spec recommended solution:
In representing Features that cross the antimeridian, interoperability is improved by modifying their geometry. Any geometry that crosses the antimeridian SHOULD be represented by cutting it in two such that neither part’s representation crosses the antimeridian. - GeoJSON Spec, 3.1.9

Error when using d3.svg.line to generate an SVG polyline from GeoJSON LIneString data

Per the suggestion in the d3.js API documentation here, I'm trying to use d3.svg.line to generate an SVG polyline from coordinate data describing a LineString in GeoJSON format. However, when I do this I get an error in my browser's JavaScript console as follows:
Error: Problem parsing d="[object SVGLineElement]"
The GeoJSON data looks like this.
test.json
{"type": "FeatureCollection", "features": [
{ "type": "Feature", "properties": { "id": "0" },
"geometry": {
"type": "LineString",
"coordinates": [
[ -122.1219348702,42.3351232329 ],
[ -122.05927795103516,43.04825098762893 ],
[ -117.5980213906,43.0866974143 ]
]
}
}
] }
The JavaScript looks like this, which follows the example in the documentation not too far below where I linked above in the section titled "Path Data Generators".
app.js
var projection = d3.geo.albers()
.scale(2000)
.center([-20,47]);
var path = d3.geo.path()
.projection(projection);
var line = d3.svg.line()
.x(function(d) { return projection(d)[0]; })
.y(function(d) { return projection(d)[1]; })
.interpolate("linear");
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
d3.json("test.json", function(json) {
g.selectAll("path")
.data(json.features)
.enter().append("path")
.attr("d", line);
I'm able to generate polygons just fine... I just run into trouble when trying to generate polylines. Any suggestions?!

Google Fusion , Map Overlays and breaking out polyline via a javascript array

My question is based on the following example from Google. I have gotten it to work great to pull out my polygon shapes from my fusion table, similar to their shapes. My issue arises when I try and alter the script to pull out some polyline data I have. The issue is in the breaking down of the rows data array. The dataset for the correct polygons is as follows.
"rows": [
[
"129",
{
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-86.3055326754,
39.8143343479,
0.0
],
[
-86.3056957826,
39.8139995783,
0.0
],
[
-86.3059116214,
39.8137158473,
0.0
],
[
-86.3055326754,
39.8143343479,
0.0
]
]
]
}
}
],etc....
The polylines is as follows
"rows": [
[
"1",
{
"geometry": {
"type": "LineString",
"coordinates": [
[
-86.2411593096,
40.1368952707,
0.0
],
[
-86.2413739094,
40.1367194041,
0.0
],
[
-86.241866376,
40.1197924711,
0.0
]
]
}
}
],etc..
The polygon has an extra [] that is throwing off my ability to parse through the data! It is driving me nuts! Serious points to answer this one! Example of mine here. I just dont know enough about javascript arrays. Thanks
Here is a version that only parses polylines:
http://www.geocodezip.com/v3_GoogleEx_FusionTables_mouseover_map_styles_polylines.html
I couldn't find any documentation or description of the expected output (other than "GeoJSON"), it would be nice if there was a way to detect polygons vs. polylines vs. markers and parse them appropriately.
Here is a description of GeoJSON
Here is a page that parse polylines, polygons and markers (not well tested).

Categories