I am try to integrate here map into our app but looks like it is getting an issue when rendering map view
This is my code
import React, { useLayoutEffect, useRef } from 'react';
import H from "#here/maps-api-for-javascript";
function MapView(): JSX.Element {
const ref = useRef();
useLayoutEffect(() => {
// `mapRef.current` will be `undefined` when this hook first runs; edge case that
if (!ref.current) return;
// instantiate a platform, default layers and a map as usual
const platform = new H.service.Platform({
apikey: process.env.REACT_APP_HERE_MAP_API_KEY,
});
const defaultLayers = platform.createDefaultLayers();
const mapView = new H.Map(
ref.current,
defaultLayers.vector.normal.map,
{
pixelRatio: window.devicePixelRatio || 1,
center: { lat: 0, lng: 0 },
zoom: 2,
},
);
// This will act as a cleanup to run once this hook runs again.
// This includes when the component un-mounts
return () => {
// eslint-disable-next-line #typescript-eslint/no-unsafe-call
mapView.dispose();
};
}, []);
return (
<div
style={{ width: '300px', height: '300px' }}
ref={ref}
/>
);
}
export default MapView;
I am using react 18 with typescript. Any idea to resolve this?
Related
I'm trying to develop a swipe component using React w/ Redux and hammerjs. The problem is that each time I move my component the position.x and position.y start from [0,0] and not from the current state they are at.
Here's the code:
import React, { useState, useEffect } from 'react';
import Hammer from 'hammerjs';
import WeatherForecast from './WeatherForecast';
const SwipeableCard = ({ children }) => {
const [gesture, setGesture] = useState(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const element = document.getElementById('swipeable-card');
const hammer = new Hammer(element);
hammer.on('pan', (event) => {
setPosition({
x: event.deltaX + position.x,
y: event.deltaY + position.y,
});
});
setGesture(hammer);
return () => {
hammer.off('pan');
setGesture(null);
};
}, []);
return (
<div
id="swipeable-card"
className="App-swipeable"
style={{
transform: `translate(${position.x}px, ${position.y}px)`,
}}
>
<WeatherForecast />
</div>
);
};
export default SwipeableCard;
i am implementing #react-google-maps/api package to draw google map on my React application, Now i have loaded geoJson its working fine. Now the requirement is i need to check whether the user click inside the geoJson data or outside and show that area detail.
import React, { useState, useCallback } from "react";
import { GoogleMap, LoadScript } from "#react-google-maps/api";
import Areas from "./GEOJSON.json";
const containerStyle = {
width: "80%",
height: "70vh",
};
const GOOGLE_API_KEY = MY_KEY;
function MyComponent() {
const [map, setMap] = useState(null);
const onLoad = useCallback(function callback(map) {
setMap(map);
map.data.addGeoJson(Areas);
}, []);
const onUnmount = useCallback(function callback(map) {
setMap(null);
}, []);
const center = {
lat: 25.2858687,
lng: 55.3281742,
};
const onClick = (e) => {
console.log("clickk", e);
};
return (
<React.Fragment>
<LoadScript
id="script-loader"
googleMapsApiKey={GOOGLE_API_KEY}
language="en"
region="us"
libraries={["drawing", "visualization", "geometry", "places"]}
>
<GoogleMap
mapContainerClassName="App-map"
zoom={12}
version="weekly"
on
mapContainerStyle={containerStyle}
center={center}
onLoad={onLoad}
onUnmount={onUnmount}
onClick={onClick}
></GoogleMap>
</LoadScript>
</React.Fragment>
);
}
export default React.memo(MyComponent);
Basically, I want to add cropping functionality. If user select a file then, user have choice to crop the image if he/she want. When I preview cropped image.
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component. This could happen for one of the following
reasons: 1. You might have mismatching versions of React and the
renderer (such as React DOM) 2. You might be breaking the Rules of
Hooks 3. You might have more than one copy of React in the same app
import React, { useEffect, useState, useRef } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
// import Styles from './Image.module.css';
const Image = (props) => {
const [crop, setCrop] = useState({
aspect: 3/4,
unit: 'px',
x: 0,
y: 0,
width: 500,
height: 500
});
const [file, setFile] = useState(null);
const [imgPreview, setImgPreview] = useState(null);
const canvasRef = useRef(null);
const filePicker = (e) => {
setFile(e.target.files[0]);
};
function image64toCanvasRef (cnvRef, image64, pixelCrop) {
const canvas = cnvRef;
canvas.width = pixelCrop.width;
canvas.height = pixelCrop.height;
const ctx = canvas.getContext('2d');
const image = new Image(); // On this line throwing error
image.src = image64
image.onload = () => {
ctx.drawImage(
image,
pixelCrop.x,
pixelCrop.y,
pixelCrop.width,
pixelCrop.height,
0,
0,
pixelCrop.width,
pixelCrop.height
)
}
}
useEffect(() => {
if (file) {
const fileReader = new FileReader();
fileReader.onload = () => {
setImgPreview(fileReader.result);
}
fileReader.readAsDataURL(file);
}
}, [file]);
const handleOnCropChanged = (crop) => {
// console.log('handleOnCropChanged: ', crop);
const state = {
...crop,
x: crop.x,
y: crop.y,
width: crop.width,
height: crop.height
}
setCrop(state);
};
const handleOnCropComplete = (crop, pixelCrop) => {
image64toCanvasRef(canvasRef.current, imgPreview, pixelCrop);
}
return (
<div
style={{
margin: '10px 28px',
}}
>
{
imgPreview ? (
<div>
<ReactCrop
src={imgPreview}
crop={crop}
keepSelection
locked
onChange={(crop) => handleOnCropChanged(crop)}
onComplete={handleOnCropComplete}
onImageLoaded={handleOnImageLoaded}
/>
</div>
) : (
<input type='file' onChange={filePicker} />
)
}
<div>
<canvas
ref={canvasRef}
></canvas>
</div>
</div>
)
};
export default Image;
I am building a React app at the moment and need to move from MapBox to Openlayers as thats what my client uses internally. Really struggling with basic functionality to get openlayers maps to react to events. At the moment, I am trying a simple 'click button, re-centre map' but can not get it to work. Can anybody help? It's got to be something simple I am doing wrong.
I am using Openlayers v 6.0.1 (ol).
import React, { useState, useEffect, useRef } from "react";
import Map from "ol/Map.js";
import View from "ol/View.js";
import Overlay from "ol/Overlay.js";
import LayerTile from "ol/layer/Tile.js";
import SourceOSM from "ol/source/OSM.js";
import * as proj from "ol/proj";
const MapView2 = () => {
// set state
const [center, setCenter] = useState(proj.fromLonLat([0, 0])); // set center of map at 0,0
const [zoom, setZoom] = useState(3); // set aoom
const posGreenwich = proj.fromLonLat([0, 51.47]);
// set initial map objects
const view = new View({
center: center,
zoom: zoom
});
const map = new Map({
target: null, // set this in componentDidMount useEffect[]
layers: [
new LayerTile({
source: new SourceOSM()
})
],
view: view
});
const overlayRef = useRef(null);
const popUpRef = useRef(null);
// useEffect Hooks
// [] = component did mount
// set the initial map targets
useEffect(() => {
map.setTarget("map");
map.on("moveend", () => {
setCenter(map.getView().getCenter());
setZoom(map.getView().getZoom());
});
// Basic overlay to show where i want the new center to be
const overlay = new Overlay({
position: posGreenwich,
element: overlayRef.current,
positioning: "center-center",
stopEvent: false
});
map.addOverlay(overlay);
// clean up upon component unmount
return () => {
console.log("will unmount");
map.setTarget(null);
};
}, []);
// ***** IT DOESNT WORK *******
useEffect(() => {
// [center, zoom] this fires after each time the center or zoom state is updated
// it should animate the view move
console.log("UseEffect Center & Zoom", center, zoom);
console.log("View", JSON.stringify(view)); // if you check this, the view correctly has a new center and zoom
// view has a new center and zoom but will not move to it automatically
// try to force it to move here
// DOESN'T WORK - how do I get the map to move???? :(
view.animate({ zoom: zoom }, { center: center }, { duration: 2000 });
}, [center, zoom]);
// helpers
const btnAction = () => {
// when button is clicked, recentre map
// this does not work :(
setCenter(posGreenwich);
setZoom(6);
};
// render
return (
<div>
<div id="map" style={{ width: "100vw", height: "100vh" }}></div>
<div
style={styles.bluecircle}
ref={overlayRef}
id="overlay"
title="overlay"
/>
<button
style={{
position: "absolute",
right: 10,
top: 10,
backgroundColor: "white"
}}
onClick={() => {
btnAction();
}}
>
CLICK
</button>
</div>
);
};
export default MapView2;
const styles = {
bluecircle: {
width: 30,
height: 30,
border: "1px solid #088",
bordeRadius: "15",
backgroundColor: "#0ff",
opacity: 0.5,
zIndex: 9999
}
};
I was having a similar problem and solved it by using useState for the map variable, such as:
const [map] = useState(
new Map({
target: null, // set this in componentDidMount useEffect[]
layers: [
new LayerTile({
source: new SourceOSM()
})
],
view: view
})
);
Then, inside useEffect:
map.getView.animate({ zoom: zoom }, { center: center }, { duration: 2000 });
I'm trying to adapt this example from https://github.com/mapbox/mapbox-react-examples/tree/master/basic,
import React from 'react'
import ReactDOM from 'react-dom'
import mapboxgl from 'mapbox-gl'
mapboxgl.accessToken = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA';
class Application extends React.Component {
constructor(props: Props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 1.5
};
}
componentDidMount() {
const { lng, lat, zoom } = this.state;
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v9',
center: [lng, lat],
zoom
});
map.on('move', () => {
const { lng, lat } = map.getCenter();
this.setState({
lng: lng.toFixed(4),
lat: lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});
}
render() {
const { lng, lat, zoom } = this.state;
return (
<div>
<div className="inline-block absolute top left mt12 ml12 bg-darken75 color-white z1 py6 px12 round-full txt-s txt-bold">
<div>{`Longitude: ${lng} Latitude: ${lat} Zoom: ${zoom}`}</div>
</div>
<div ref={el => this.mapContainer = el} className="absolute top right left bottom" />
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById('app'));
to a case in which, rather than displaying the map's center, I would like to display the latitude and longitude of the mouse position.
So far, I've managed to simply log it to the console:
import React from 'react';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'pk.eyJ1Ijoia3VydHBlZWsiLCJhIjoiY2p6cnVneWdvMHlzeDNqcWo0dm83ZzZ2eiJ9.yUCSreTRcKs12uT5PTCztg';
export default class Map extends React.Component {
componentDidMount() {
this.map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/outdoors-v11',
center: [-119.5591, 37.715],
zoom: 9
});
this.map.on('load', function(e) {
e.target.on('mousemove', function(e) {
console.log(JSON.stringify(e.point));
console.log(JSON.stringify(e.lngLat.wrap()));
});
});
}
componentWillUnmount() {
this.map.remove();
}
render() {
const style = {
position: 'absolute',
top: 0,
bottom: 0,
width: '100%'
};
return <div style={style} ref={el => this.mapContainer = el} />;
}
}
This writes lines like the following to the console:
{"x":972,"y":272}
{"lng":-118.90266689452113,"lat":37.86205552587528}
However, rather than logging the coordinates to the console, I would like to invoke this.setState() like in the example so that I can render the coordinates in a child component.
The problem is, within the on('mousemove', ...) callback function, this is not the component. I've read about using arrow functions (which are lexically scoped) to work around this, but it seems to me that in this case, I need a 'normal' function(e) in order to capture the event.
How can I setState() with the mouse coordinates in this example?
It's possible to use arrow functions just like any other function
this.map.on('load', e => {
e.target.on('mousemove', e => {
this.setState({}) //correct this
})
})