react map leaflet circleMarker doesn't render - reactjs

I have a leaflet map, and I have one button. I want to display some circlesMarker when I click on a button and remove the circlesMarker when I click again (remove option is not implemented yet)
I don't want to render each time all map when I click the button, I want render only the circleMarker.
CircleMarker doesn't render on a map, but I can see the map
Here my code :
COMPONENT MAP
function Map1() {
const apartments = [
{ roomType: 'shared room', geometry: [41.402610, 2.204270] },
{ roomType: 'shared room', geometry: [41.411300, 2.217630] },
{ roomType: 'private room', geometry: [41.410220, 2.212520] },
{ roomType: 'apartament sencer', geometry: [41.410630, 2.216970] },
{ roomType: 'private room', geometry: [41.409190, 2.209030] },
]
let map = useRef(null);
useEffect(() => {
let url = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}'
const access = 'pk.eyJ1Ijoiam9zZXQyMSIsImEiOiJjazF1bGZlcHowYjVlM2RwYW9ia2pwaWtlIn0.9n-6tKArfdSfd15Do6YxLA'
map.current = L.map("map");
const defaultCenter = [41.383, 2.173];
const defaultZoom = 13.10;
let layer = L.tileLayer(url, {
maxZoom: 18,
id: 'mapbox.streets',
accessToken: access,
});
map.current.setView(defaultCenter, defaultZoom);
layer.addTo(map.current);
}, [map])
const handleOnclik = (e) => {
e.preventDefault()
let color = (e.target.name)
if (color === 'pink') {
apartments.map(item => {
if (item.roomType === 'private room' || item.roomType === 'shared room') {
return (
<div>
<p>Carme</p>
<CircleMarker className="circle"
center={[41.409190, 2.209030]}
color={'#000080'}
width={.5}
fillColor={'blue'}
fillOpacity={0.5}
stroke={'black'}
>
</CircleMarker >
</div>
)
}
})
}
return (<>
<div className="container">
<div>
<div id="map" className="normalscreen"></div>
</div>
<div id="basemaps-wrapper" className="leaflet-bar">
<select id="basemaps">
<option>Visualització</option>
<option value="mapbox.streets">Streets</option>
<option value="mapbox.satellite">Satellite</option>
<option value="mapbox.outdoors">Outdoors</option>
<option value="mapbox.dark">Dark</option>
<option value="mapbox.light">Light</option>
<option value="mapbox.DarkGray">Dark Gray</option>
</select>
<button onClick={onChangeFullScreen}>Full Screen</button>
<div>
<img onClick={handleOnclik} name="pink" src="images/pink" alt="habitacio" />
<img onClick={handleOnclik} name="green" src="images/green" alt="apartament" />
</div>
</div>
</div>
</>)
}
export default Map1
MAP CSS
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.container {
display: flex;
flex-direction: column;
width: 100vw;
justify-content: center;
}
#map {
display: block;
}
.normalscreen {
width: 50%;
height: 50vh;
left: 49%;
position: relative;
}
.fullscreen {
width: 100%;
height: 80vh;
left: 0%;
text-align: center;
}
APP
import React from 'react'
import { withRouter } from 'react-router-dom'
import Navbar from './Navbar'
import Map from './Map'
function App() {
return (<>
<Navbar />
<Map />
</>);
}
export default withRouter(App)

There is no CircleMarker component on leaflet library exposed unless you use react-leaflet which you don't. Therefore here is the code you need to use in order to add to the map circle markers:
const handleOnclik = () => {
apartments.forEach(({ geometry }) => {
new L.CircleMarker(geometry, {
radius: 5,
fillColor: "blue",
width: 0.5,
stroke: "black",
color: "#000080",
fillOpacity: 0.5
}).addTo(map.current);
});
};
I removed the if statements for simplicity just to illustrate an example.
Demo

Related

How can I upload Images with Preview in React

I've been trying to upload multiple images WITH preview in NextJS (React). I tried changing the constants to arrays and tried mapping through them but it just doesn't seem to work and I don't know how I could get it to work.
I've made a component out of the upload functionality and here is the code that works for uploading a single image with a Preview.
uploadImage.js
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
function imageUpload() {
const [image, setImage] = useState(null);
const fileInputRef = useRef();
const [preview, setPreview] = useState();
useEffect(() => {
if (image) {
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
};
reader.readAsDataURL(image);
} else {
}
}, [image]);
return (
<div className="flex ">
<StyledImg
src={preview}
style={{ objectFit: "cover" }}
onClick={() => setImage(null)}
/>
<StyledButton
onClick={(e) => {
e.preventDefault();
fileInputRef.current.click();
}}
/>
<input
type="file"
style={{ display: "none" }}
accept="image/*"
ref={fileInputRef}
onChange={(e) => {
const file = e.target.files[0];
if (file && file.type.substr(0, 5) === "image") {
setImage(file);
} else {
setImage(null);
}
}}
/>
</div>
);
}
const StyledButton = styled.button`
`;
const StyledImg = styled.img`
width: 100px;
height: 100px;
margin-right: 10px;
`;
export default imageUpload;
Based on these references https://react-dropzone.js.org/#section-previews and https://stackblitz.com/edit/nextjs-buk2rw?file=pages%2Findex.js I replaced my code with the following
ImageUpload.js
import React, { useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import styled from "styled-components";
function DragAndDrop() {
const [files, setFiles] = useState([]);
const { getRootProps, getInputProps } = useDropzone({
accept: "image/*",
onDrop: (acceptedFiles) => {
setFiles((files) => [
...files,
...acceptedFiles.map((file) =>
Object.assign(file, {
key: file.name + randomId(), // to allow adding files with same name
preview: URL.createObjectURL(file),
})
),
]);
},
});
const removeFile = (file) => {
setFiles((files) => {
const newFiles = [...files];
newFiles.splice(file, 1);
return newFiles;
});
};
const thumbs = files.map((file, i) => (
<div style={thumb} key={file.key}>
<div style={thumbInner}>
<img src={file.preview} style={img} />
</div>
<button type="button" style={removeButton} onClick={() => removeFile(i)}>
X
</button>
</div>
));
useEffect(
() => () => {
files.forEach((file) => URL.revokeObjectURL(file.preview));
},
[files]
);
return (
<section className="container">
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<StyledP className="flex align-center justify-center">
Glisser Images Ici ou Cliquer pour selectionner
</StyledP>
</div>
<aside style={thumbsContainer}>{thumbs}</aside>
</section>
);
}
const StyledP = styled.p`
cursor: pointer;
padding: 30px;
`;
const randomId = () => (Math.random() + 1).toString(36).substring(7);
const thumbsContainer = {
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
marginTop: 16,
};
const thumb = {
display: "inline-flex",
borderRadius: 2,
border: "1px solid #eaeaea",
marginBottom: 8,
marginRight: 8,
width: 100,
height: 100,
padding: 4,
boxSizing: "border-box",
position: "relative",
};
const thumbInner = {
display: "flex",
minWidth: 0,
overflow: "hidden",
};
const img = {
display: "block",
width: "auto",
height: "100%",
};
const removeButton = {
color: "red",
position: "absolute",
right: 4,
};
export default DragAndDrop;

Material UI pagination - How Can I use custom style for number of pages?

I'm quite new to material-ui. I'm trying to build this component.
I was able to do the style for the next and previous buttons the same as in the picture.
The normal style shows the number of pages as a numbered group besides each other like this:
Are there any properties that I can pass for the pagination component, in which I can change the style?
Here is the code:
import Pagination from "#material-ui/lab/Pagination";
import useStyles from "./styles";
const ReviewsPagination = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Pagination count={8} />
</div>
);
};
export default ReviewsPagination;
and the style file:
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
root: {
"& .MuiPagination-ul": {
"& > li:first-child": {
"& button": {
borderRadius: "50%",
border: "1px solid black",
width: "48px",
height: "48px",
},
},
"& > li:last-child": {
"& button": {
borderRadius: "50%",
border: "1px solid black",
width: "48px",
height: "48px",
},
},
},
},
});
export default useStyles;
Thank you!
you can use the usePagination hook to customize the pagination component. Like below:
export default function UsePagination() {
const classes = useStyles();
const { items } = usePagination({
count: 10,
});
return (
<nav>
<ul className={classes.ul}>
{items.map(({ page, type, selected, ...item }, index) => {
let children = null;
if (type === 'next' || type === 'previous') {
children = (
<button type="button" {...item}>
{type}
</button>
);
}else if(selected){
children = <div>{`${page}/10`}</div>
}
return <li key={index}>{children}</li>;
})}
</ul>
</nav>
);
}

React-select, open sub-menu when hover over an option

I'm trying to build a submenu inside a main menu with React-select, it should be something like this:
When hovering over an option from the main menu, it triggers the submenu to open at the side.
Is there a way to do this using react-select? I couldn't find any example or documentation on this, is there a function like ```optionOnMouseover`` for this? Thank you in advance!
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
...
<Select
value={...}
onChange={...}
options={options}
/>```
This is on click, but if you need on hover,
just modify it
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select, { components } from "react-select"
const CustomOption = (props) => {
const [submenu, setSubmenu] = useState(false)
const [height, setHeight] = useState(0)
const handleOption = (e) => {
if(submenu) {
setSubmenu(false)
} else {
setHeight(e.clientY)
setSubmenu(true)
}
}
const handleSubOption = (e) => {
console.log('clicked')
}
const { data } = props;
return data.custom ? (
<>
<div onClick={handleOption} className="customs">
{data.label} <span className="caret"/>
{
submenu && (
<div className="dropdown-submenu">
<div className="drops" onClick={handleSubOption}>
Test dropdown 1
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 2
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 3
</div>
</div>
)
}
</div>
<style jsx>{`
.customs {
height: 36px;
padding: 8px;
position: relative;
}
.drops {
height: 36px;
padding: 8px;
}
.customs:hover, .drops:hover {
background-color: #17cf76;
}
.dropdown-submenu {
position: fixed;
top: ${height - 10}px;
left: 410px;
min-height: 36px;
overflow: auto;
border: 1px solid hsl(0,0%,80%);
border-radius: 4px;
color: #212529;
}
`}</style>
</>
) : (
<components.Option {...props} />
);
};
const options = [
{ custom: true, label: "I'm a custom link", value: "cust" }
];
function App() {
return (
<>
<Select classNamePrefix="category-select" className="w-30" components={{ Option: CustomOption }} options={options} />
<style jsx global>{`
* {
font-family: sans-serif;
text-align: center;
}
.w-30 {
width: 30% !important;
}
`}</style>
</>
)
}
export default App

how to style HTML when using react-native-print

So what I am trying to print out html but with little styling i tried everything that i know of but I was't able to get it done.Every thing is working fine thought can't style the Html.I even tried to bind it with the style tag properties but still it didn't worked.
My code is
import React, { Component } from 'react';
import {
AppRegistry,
Button,
StyleSheet,
NativeModules,
Platform,
Text,
View
} from 'react-native';
import RNPrint from 'react-native-print';
export default class RNPrintExample extends Component {
state = {
selectedPrinter: null
}
// #NOTE iOS Only
selectPrinter = async () => {
const selectedPrinter = await RNPrint.selectPrinter()
this.setState({ selectedPrinter })
}
// #NOTE iOS Only
silentPrint = async () => {
if (!this.state.selectedPrinter) {
alert('Must Select Printer First')
}
const jobName = await RNPrint.print({
printerURL: this.state.selectedPrinter.url,
html: '<h1>Silent Print</h1>'
})
}
//trying to style this HTML
async printHTML() {
await RNPrint.print({
html: '<h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3>'
})
}
async printRemotePDF() {
await RNPrint.print({ filePath: 'https://graduateland.com/api/v2/users/jesper/cv' })
}
customOptions = () => {
return (
<View>
{this.state.selectedPrinter &&
<View>
<Text>{`Selected Printer Name: ${this.state.selectedPrinter.name}`}</Text>
<Text>{`Selected Printer URI: ${this.state.selectedPrinter.url}`}</Text>
</View>
}
<Button onPress={this.selectPrinter} title="Select Printer" />
<Button onPress={this.silentPrint} title="Silent Print" />
</View>
)
}
render() {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && this.customOptions()}
<Button onPress={this.printHTML} title="Print HTML" />
<Button onPress={this.printPDF} title="Print PDF" />
<Button onPress={this.printRemotePDF} title="Print Remote PDF" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
Any help Would be Appreciated.
<html>
<head>
<style>
.heading{
background-color: red;
}
.block {
background-color: black;
height: 30;
}
.text{
color: white;
}
</style>
</head>
<body>
<h1 class='heading'>Title</h1>
<div class='block'>
<span class='text'>Hello, World !</span>
</div>
</body>
I was able to style it by storing the above HTML inside back-ticks (``) and using it like
RNPrint.print({
html: `<html>... ....</html>`
})
you can use this as a guide. worked well for me.
<page size="A4"></page>
<page size="A4"></page>
<page size="A4" layout="landscape"></page>
<page size="A5"></page>
<page size="A5" layout="landscape"></page>
<page size="A3"></page>
<page size="A3" layout="landscape"></page>
body {
background: rgb(204,204,204);
}
page {
background: white;
display: block;
margin: 0 auto;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0,0,0,0.5);
}
page[size="A4"] {
width: 21cm;
height: 29.7cm;
}
page[size="A4"][layout="landscape"] {
width: 29.7cm;
height: 21cm;
}
page[size="A3"] {
width: 29.7cm;
height: 42cm;
}
page[size="A3"][layout="landscape"] {
width: 42cm;
height: 29.7cm;
}
page[size="A5"] {
width: 14.8cm;
height: 21cm;
}
page[size="A5"][layout="landscape"] {
width: 21cm;
height: 14.8cm;
}
#media print {
body, page {
margin: 0;
box-shadow: 0;
}
}
https://codepen.io/rafaelcastrocouto/pen/LFAes

React Component wont render in Codepen

I have a simple radio button group component on codepen here that is not rendering in codepen. I want to post this to the code review stackexchange, since it is one of the first components i've built and will be necessary in many places on a web app I am building. However for that post, I want my codepen example to be working.
I think I am probably breaking some rule about how to use es6 in react to get the app to render, but I am struggling to debug. My console.logs() are not helping, and the error messages in codepen arent helping a ton either.
Since I linked to my codepen, I have to accompany it with code, so here's what I have in my codepen at the moment:
import React, { Component } from 'react';
import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap';
class ToolButtonGroup extends Component {
constructor(props) {
super(props);
};
render() {
// Get Variables from the params prop
const { header, buttons, initialVal } = this.props.params;
const { borderRadius, margin, padding, fontsize, border } = this.props.params;
const { gridID, gridColumns, minRowHeight } = this.props.params;
// Create the individual buttons
const pageButtons = buttons.map((buttoninfo, idx) => {
return (
<ToggleButton
key={idx}
style={{
"borderRadius": borderRadius,
"margin": margin,
"padding": padding,
"fontSize": fontsize,
"border": border
}}
bsSize="large"
value={buttoninfo.value}>
{buttoninfo.label}
</ToggleButton>
)
})
// Return the button group
return(
<div
style={{"border": "1px solid red" }}
id={gridID}>
<h2 style={{
"width": "100%",
"margin": "0 auto",
"fontSize": "1.75em",
"marginTop": "5px",
"border": "none"
}}
>{header}</h2>
<ToggleButtonGroup
type="radio"
name="charttype-options"
defaultValue={initialVal}
onChange={this.props.handler}
style={{
"display": "grid",
"gridTemplateColumns": "repeat(" + gridColumns + ", 1fr)",
"gridAutoRows": "auto",
"gridGap": "8px"
}}
>
{pageButtons}
</ToggleButtonGroup>
</div>
)
}
}
class StarterApp extends Component {
constructor(props){
super(props);
this.state = {
pitchersOrHitters: "",
position: ""
}
}
// Button and Select Handlers!
handlePitchHitChange = (pitchersOrHitters) => {
this.setState({pitchersOrHitters})
}
handlePositionChange = (position) => {
this.setState({ position: position });
}
render() {
console.log("A")
// 0. Load State and Props
const { pitchersOrHitters, position } = this.state;
// Pitcher or Hitter Radio Button Group params
const pitchOrHitButtonGroup = {
borderRadius: "25px",
margin: "1% 10%",
padding: "5%",
fontsize: "2em",
border: "2px solid #BBB",
gridColumns: 1, minRowHeight: "10px", "gridID": "buttons1",
header: "Choose One:",
buttons: [
{ value: "Pitchers", label: "Pitchers" },
{ value: "Hitters", label: "Hitters" },
],
initialVal: "Pitchers"}
// Pitcher or Hitter Radio Button Group params
const positionButtonGroup = {
borderRadius: "10px",
margin: "1% 10%",
padding: "5%",
fontsize: "1.25em",
border: "2px solid #BBB",
gridColumns: 4, minRowHeight: "20px", "gridID": "buttons2",
header: "Choose One:",
buttons: [
{ value: "SP", label: "SP" },
{ value: "RP", label: "RP" },
{ value: "1B", label: "1B" },
{ value: "2B", label: "2B" },
{ value: "SS", label: "SS" },
{ value: "3B", label: "3B" },
{ value: "LF", label: "LF" },
{ value: "RF", label: "RF" },
{ value: "CF", label: "CF" }
],
initialVal: "SP"}
return(
<div className="chart-grid-container">
<ToolButtonGroup
params={pitchOrHitButtonGroup}
value={pitchersOrHitters}
handler={this.handlePitchHitChange} />
<ToolButtonGroup
params={positionButtonGroup}
value={position}
handler={this.handlePositionChange} />
</div>
)
}
}
ReactDOM.render(
<StarterApp />,
document.getElementById('root')
);
.chart-grid-container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: minmax(200px, auto);
grid-gap: 5px;
grid-template-areas:
"btns1 btns1 btns2 btns2 btns2 btns2 . . . . . .";
}
#buttons1 { grid-area: btns1; }
#buttons2 { grid-area: btns2; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react-dom.min.js"></script>
<div id='root'>
COME ON WORK!
</div>
Im unsurprisingly struggling to get this code snippet working as well. Although in this case, it is because I don't know how to include react-bootstrap, which is something I've already done in my codepen.
Thanks!
I noticed I got the errors when using import statements on that specific project.
This is probably a limitation of transpiling engine on the codepen. Better if you use some platform (ie: enter link description here) that already has all of these solved out for you.
Here is your code on codesandbox.

Resources