Rendering vector-tiles using Mapbox using react-mapbox-gl - reactjs

I have a geoJSON file that I convert into vector.tiles using this npm package.
I use const tileIndex = geojsonvt(geoJSON). The geoJSON file has the following format and it gets converted without any error.
const geoJSON = {
type: 'FeatureCollection',
crs: {
type: 'name',
properties: { name: 'urn:ogc:def:crs:OGC:1.3:CRS84' }
},
features: [
{
properties: [Object],
geometry: [Object],
type: 'Feature',
_id: '5ed7b221a61a4b2970433932'
},
... 1840 more items
]
}
The result (geoJSON vector-tiles) that I get after conversion is following -
const tiles = {
options: {},
tiles: {
'0': {
features: [Array],
numPoints: 540529,
numSimplified: 3,
numFeatures: 1940,
source: null,
x: 0,
y: 0,
z: 0,
transformed: false,
minX: 0.5162953202777778,
minY: 0.316725863688461,
maxX: 0.5338655772222223,
maxY: 0.34955196703359503
},
'1': { ... }
},
tileCoords: [
{ z: 0, x: 0, y: 0 }, { z: 1, x: 1, y: 1 },
{ z: 1, x: 1, y: 0 }, { z: 2, x: 3, y: 1 },
{ z: 2, x: 3, y: 0 }, { z: 2, x: 2, y: 1 },
{ z: 3, x: 5, y: 3 }, { z: 3, x: 5, y: 2 },
{ z: 3, x: 4, y: 3 }, { z: 3, x: 4, y: 2 },
{ z: 4, x: 9, y: 5 }, { z: 4, x: 9, y: 4 },
{ z: 4, x: 8, y: 5 }, { z: 5, x: 17, y: 11 },
{ z: 5, x: 17, y: 10 }, { z: 5, x: 16, y: 11 },
{ z: 5, x: 16, y: 10 }, { z: 4, x: 8, y: 4 },
{ z: 2, x: 2, y: 0 }, { z: 1, x: 0, y: 1 },
{ z: 1, x: 0, y: 0 }
]
}
After converting a huge geoJSON file with 5000 layers into vector tiles, I am sending this data to the client-side wherein I render Map using React.js and Mapbox*. I use following to render the map but I have not been able to figure out what I am doing wrong. The error that I get says error: layers.jsx-layer-0: layer "jsx-layer-0" must specify a "source-layer"
<Source type="vector" tiles={data.tiles} >
<Layer {...dataLayer}/>
</Source>
I went through the documentation of Mapbox for the same but I'm unable to find what I am doing wrong. Any help would be of great help. Thank you very much.

react-mapbox-gl is in many places just a wrapper around mapbox-gl, and if you look at the documentation there:
https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/#tiled-sources
You will see that the "tiles" property is only for url sources, where as the "url" property can be used to load a file with tiles:
"url": "http://api.example.com/tilejson.json"

The docs indicate that the source-layer is required field for vector layers.
That said, it certainly opaque as to how this works in a declarative api. Based on example, you might try this to see if it works -
...
const url = 'mapbox://mapbox.mapbox-terrain-v2'
const source = 'my-source';
<Source id={{source}} name={{source}} type="vector" url={url} tiles={data.tiles} >
<Layer source={{source}} {...dataLayer}/>
</Source>
...

rendering a layer with it source so you need to referrer to source id in layer + you need to add a source-layer prop like this:
<Source id='contours' type='vector' url='mapbox://mapbox.mapbox-terrain-v2' tileJsonSource={data.tiles}/>
<Layer
id='contours'
type='line'
source='contours'
source-layer='contour'
paint={{
'line-color': '#877b59',
'line-width': 1
}}
/>
</MapGL>;

Related

How can I add object in array as value length?

I'd like to know how i can add object in array length.
I asked this question before,
and I got the hint at the moment but i can't still figure it out how to do it ,
so here is my piece code :
const [data, setdata] = useState([
{ x: 1, y: 2 },
{ x: 1, y: 2 },
{ x: 1, y: 2 },
]);
const newData = [3, 4, 5, 6, 7, 8, 9];
const updateX = () => {
setdata((data) => data.map((d, i) => ({ ...d, x: newData[i] })));
};
/////result ///
{ x: 3, y: 2 },
{ x: 4, y: 2 },
{ x: 5, y: 2 },
/// what i want ///
{ x: 3, y: 2 },
{ x: 4, y: 2 },
{ x: 5, y: 2 },
{ x: 6, y: 2 },
{ x: 7, y: 2 },
{ x: 8, y: 2 },
{ x: 9, y: 2 },
The problem here is that you are mapping over data which only has 3 elements. Therefore, the final result will only have 3 elements.
To create a new array from newData, then you must use newData.map() instead of data.map(). The simplest way would be to do it directly:
newData.map(item => {x: item, y: 2})
You can update like this:
const updateX = () => {
setdata(newData.map((item, i) => ({ x: item, y: data[i] ?? 2 })));
};

Plotly React keep zoom and rotation between re-rendering

I'm using the React version of plot.ly to render a 3D scatter plot, but every time I re-render my component, the plot gets reset to its default configuration.
How can I prevent this, and keep the zoom/rotation configuration?
Below is a minimal code example. To re-iterate, how can I save the zoom and rotation, and how can I set it on the plot?
setPlotData() {
const points = {
1: {x: 1, y: 1, z: 1},
2: {x: 2, y: 1, z: 1},
3: {x: 3, y: 2, z: 1}
}
const x=[], y=[], z=[]
Object.keys(points).forEach((key, index) => {
x.push(points[key].x); y.push(points[key].y); z.push(points[key].z)
})
const data1 = {
x: x, y: y, z: z,
mode: "markers",
marker: {
color: "rgb(16, 52, 166)",
size: 4,
symbol: "circle",
opacity: 1
},
type: "scatter3d"
}
this.setState({
scatterPlotData: [data1]
})
}
render() {
return(
<Plot
data={this.state.scatterPlotData}
layout={{
autosize: true,
l: 0, r: 0, b: 0, t: 0, pad: 0,
showlegend: false,
margin:{l:0,r:0,b:0,t:0}
}}
style={{ width: '100%', height: '100%' }}
/>
)
}
Update the layout to add uirevision parameter
layout={{
autosize: true,
l: 0, r: 0, b: 0, t: 0, pad: 0,
showlegend: false,
margin:{l:0,r:0,b:0,t:0},
xaxis: {
uirevision: 'time',
},
yaxis: {
uirevision: 'time',
},
}}
you can change the uirevision: "time" to whatever x,y axis parameters you use

React Grid Layout - Grid Item shown on screen even though not within layout

I am using react-grid-layout to try to make a resizable grid. I also tried adding the functionality to remove grid items. However, upon removal of grid item (which in actual fact just removes that item from the layout object passed in, the grid item would then change to the smallest size possible, but still stay on the screen. Is there any reason for this? enter image description here
Before removing from layout
After removing from layout
Here is the layout object:
before
{ i: 'card', x: 0, y: 0, w: 5, h: 8, minH: 8, },
{ i: 'calendar', x: 0, y: 8, w: 5, h: 25 },
{ i: 'forecast', x: 5, y: 0, w: 5, h: 18 },
{ i: 'workflow', x: 5, y: 18, w: 2, h: 15 },
{ i: 'activities', x: 7, y: 18, w: 3, h: 15 },
after removing
{ i: 'calendar', x: 0, y: 8, w: 5, h: 25 },
{ i: 'forecast', x: 5, y: 0, w: 5, h: 18 },
{ i: 'workflow', x: 5, y: 18, w: 2, h: 15 },
{ i: 'activities', x: 7, y: 18, w: 3, h: 15 },
after removing and when onLayoutChange is called
{ i: 'card', x: 0, y: 0, w: 1, h: 1 },
{ i: 'calendar', x: 0, y: 1, w: 5, h: 25 },
{ i: 'forecast', x: 5, y: 0, w: 5, h: 18 },
{ i: 'workflow', x: 5, y: 18, w: 2, h: 15 },
{ i: 'activities', x: 7, y: 18, w: 3, h: 15 },
Why is it that the removed grid item still appears on the screen? I removed it onClick of the 'X' button, by removing that grid item from the layout object, however, right after it is removed, the onLayoutChange method is called, and it adds that 'card' back into the layout object, just with the smallest size. Is there any reason for this? I am new to using react-grid-layout, do let me know if I did anything wrong!
Here is my code for the grid
const layout = useSelector(state => state.layout.project.pre_layout)
// this layout is the layout object shown above, taken from redux store
const onLayoutChange = (layout, layouts) => {
console.log(layout);
console.log(layouts);
dispatch({ type: "LAYOUT_ONCHANGE", layout: layouts, page: 'project' })
// this dispatch updates the redux store with the new layout
}
<ResponsiveGridLayout className="layout" layouts={layout}
onLayoutChange={(layout, layouts) =>
onLayoutChange(layout, layouts)
}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
rowHeight={row_height}
compactType={'vertical'}
preventCollision={false}>
/* content here */
</ResponsiveGridLayout>
Thanks all
Bit late but I've just encountered this myself so figured I'd put my findings!
If you just remove the layout details for an item but leave it in the content - it'll stay on the grid but reset back to default position and dimension.
To remove an item completely you'll need to remove it from both the layout and the content. Content being whatever you're displaying in /* content here */

React-Grid-Layout elements handle jumps if there are other elements in the app root in react app

My React-Grid-Layout elements handle jumps if there are other elements in the app root in my react app.
If I remove the navbar component above the responsive grid layout I am able to click and drag properly, otherwise, when I try to click on the responsive grid layout element it jumps down.
Here's my code:-
App.js
import React from 'react';
import './App.css';
import '#devexpress/dx-react-grid-bootstrap4/dist/dx-react-grid-bootstrap4.css';
import PyfinNavbar from './components/navbar';
import HomeView from './home';
import PyfinResponsiveGrid from './ResponsiveGridLayout';
function App() {
return (
<div className="App">
<PyfinNavbar></PyfinNavbar>
<HomeView></HomeView>
<PyfinResponsiveGrid></PyfinResponsiveGrid>
</div>
);
}
export default App;
PyfinResponsiveGridLayout.jsx
import React from "react";
import { Responsive as ResponsiveGridLayout } from "react-grid-layout";
import PyfinGrid from "./grid";
let layouts = {
lg: [
{ h: 2, w: 2, x: 0, y: 0 },
{ h: 2, w: 2, x: 1, y: 0 },
{ h: 2, w: 2, x: 2, y: 0 },
{ h: 2, w: 2, x: 3, y: 0 }
],
sm: [
{ h: 2, w: 2, x: 0, y: 0 },
{ h: 2, w: 2, x: 1, y: 0 },
{ h: 2, w: 2, x: 2, y: 0 },
{ h: 2, w: 2, x: 3, y: 0 }
],
md: [
{ h: 2, w: 2, x: 0, y: 0 },
{ h: 2, w: 2, x: 1, y: 0 },
{ h: 2, w: 2, x: 2, y: 0 },
{ h: 2, w: 2, x: 3, y: 0 }
],
xs: [
{ h: 2, w: 2, x: 0, y: 0 },
{ h: 2, w: 2, x: 0, y: 1 },
{ h: 2, w: 2, x: 0, y: 2 },
{ h: 2, w: 2, x: 0, y: 3 }
],
xxs: [
{ h: 2, w: 2, x: 0, y: 0 },
{ h: 2, w: 2, x: 0, y: 1 },
{ h: 2, w: 2, x: 0, y: 2 },
{ h: 2, w: 2, x: 0, y: 3 }
]
};
class PyfinResponsiveGrid extends React.Component {
render() {
return (
<ResponsiveGridLayout
className="layout"
layouts={layouts}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
>
<div className="widgetborder" key="1">
<PyfinGrid></PyfinGrid>
</div>
</ResponsiveGridLayout>
);
}
}
export default PyfinResponsiveGrid;
grid.jsx
import React from "react";
import { PagingState, IntegratedPaging } from "#devexpress/dx-react-grid";
import {
Grid,
Table,
TableHeaderRow,
PagingPanel
} from "#devexpress/dx-react-grid-bootstrap4";
import customers from "./customers";
const GridView = () => (
<Grid
rows={customers}
columns={[
{ name: "customerID", title: "ID" },
{ name: "companyName", title: "Company" },
{ name: "contactName", title: "Name" },
{ name: "contactTitle", title: "Title" },
{ name: "address", title: "Address" }
]}
>
<PagingState defaultCurrentPage={0} pageSize={1} />
<IntegratedPaging />
<Table />
<TableHeaderRow />
<PagingPanel />
</Grid>
);
class PyfinGrid extends React.Component {
state = {};
render() {
return (
<div>
<GridView></GridView>
</div>
);
}
}
export default PyfinGrid;
Basically I am trying to create something like
https://www.bitmex.com/app/trade/XRPH20
It uses the same gridlayout control but when I use devextreme react grid in the layout the above mentioned problem happens.
This solved the issue for me - see comment.
.react-grid-layout {
position: relative;
}

Get max of x axis in highcharts using react

I am trying to get the max value of the x axis and set an annotation just at the end:
y: chart.xAxis[0].max-1
What is the right syntax to get it working in react? See a live demo here.
You can not use values from the chart in options. You should add your annotations dynamically in addAnnotation method:
chart: {
events: {
load: function(){
const chart = this;
chart.addAnnotation({
labels: [
{
point: {
x: 3,
y: chart.xAxis[0].max - 1,
xAxis: 0,
yAxis: 0
},
text: "x: {x}<br/>y: {y}"
},
{
point: {
x: 0,
y: 0
},
text: "x: {point.plotX} px<br/>y: {point.plotY} px"
},
{
point: {
x: 5,
y: 100,
xAxis: 0
},
text: "x: {x}<br/>y: {point.plotY} px"
}
],
labelOptions: {
x: 40,
y: -10
}
})
}
}
}
Live demo: https://codesandbox.io/s/537kz8xwyx

Resources