【问题标题】:How can I remove markers from the map using the checkboxes on the left?如何使用左侧的复选框从地图中删除标记?
【发布时间】:2020-04-03 17:35:28
【问题描述】:

这是我正在进行的应用程序。我的目标是在地图上显示冲浪点的当前风速和难度级别(基于风速的高低)

https://lewisd1996.github.io/surferspotter/

我是 React 的新手,我还在学习中。

如何使用左侧的复选框更改地图上的标记。

这是我的 SurfMap 课程:

import React, { Component } from 'react';
import L from 'leaflet';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import main from '../styles/main.scss';
import SpotList from "./SpotList.js";
import Spot from "./Spot.js";
import axios from 'axios';
import jsonLocations from '../jsonLocations.json';

export default class SurfMap extends Component {

    constructor() {
        super()
        this.state = {
            spots: [], //THE ARRAY THAT WILL HOLD THE LIST OF SURFING SPOTS
        }
        }

    getSpots = () => { //THE FUNCTION TO POPULATE THE LIST OF SPOTS USING AXIOS

       axios.get("https://api.jsonbin.io/b/5e8733f193960d63f0782ad5/2")
        .then(res => {
            this.setState({
                spots: res.data
            });
        });

    }

    componentDidMount(){
        this.getSpots();
    }

    render() {
        var startPosition = [36.778259, -119.417931] //STARTING POSITION OF THE MAP
        return (
            <>
            {this.state.spots.length ? 
                <Map className="map" center={startPosition} zoom={5}>
                    <TileLayer
                        attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                        />
                    {this.state.spots.map (spot => //LOOP THROUGH THE LIST OF SPOTS AND CREATE A SPOT FOR EACH ONE TO BE PLOTTED ONTO THE MAP
                        <Spot {...spot} />
                    )}
                </Map>:
        <p>loading data....</p>}
      </>

        )
    }
}

这是我的 Spot 课程(地图上绘制的冲浪点):

import React, { Component, setState } from 'react'
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import L from 'leaflet';
import axios from 'axios';
import main from '../styles/main.scss'

var owmApiKey = 'HIDING THIS FROM STACKOVERFLOW';

var beginnerIcon = L.icon({ //SETS UP THE PIN ICON THAT IS USED TO PLOT MARKERS ON THE MAP
    iconUrl: process.env.PUBLIC_URL + '/markers/Green-marker.png',
    iconSize: [41,41],
    iconAnchor: [12.5,41],
    popupAnchor: [0, -41]
});

var intIcon = L.icon({ //SETS UP THE PIN ICON THAT IS USED TO PLOT MARKERS ON THE MAP
    iconUrl:  process.env.PUBLIC_URL + '/markers/Red-marker.png',
    iconSize: [41,41],
    iconAnchor: [12.5,41],
    popupAnchor: [0, -41]
});

var expertIcon = L.icon({ //SETS UP THE PIN ICON THAT IS USED TO PLOT MARKERS ON THE MAP
    iconUrl: process.env.PUBLIC_URL + '/markers/Purple-marker.png',
    iconSize: [41,41],
    iconAnchor: [12.5,41],
    popupAnchor: [0, -41]
});


export default class Spot extends Component {

    constructor(props) {
        super()
        this.state = {
            county_name: props.county_name,
            latitude: props.latitude,
            longitude: props.longitude,
            spot_id: props.spot_id,
            spot_name: props.spot_name,
            wind_speed: 0,
        }
    }

    getWindSpeed = (latitude, longitude) => {//THE FUNCTION TO POPULATE THE LIST OF SPOTS USING AXIOS
            axios.get(`https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${latitude}&appid=${owmApiKey}`)
            .then(res => {
                this.setState({
                    wind_speed: (res.data.wind.speed * 1.944)
                });
            });
    }

    componentDidMount() {
        this.getWindSpeed(this.state.latitude,this.state.longitude);
    }


    render() {
        return(
        <>
            {(() => {
            if (this.state.wind_speed < 8) {
                return (
                    <Marker position={[this.state.latitude,this.state.longitude]} icon={beginnerIcon} className="beginner-marker">
                    <Popup >
                        <p className="marker-label">{this.state.spot_name + ", " + this.state.county_name}<br/>Wind Speed: {this.state.wind_speed} knots<br/>Difficulty: Beginner</p>
                    </Popup>
                    </Marker>    
                )
            } else if (this.state.wind_speed > 8 && this.state.wind_speed < 16) {
                return (
                    <Marker position={[this.state.latitude,this.state.longitude]} icon={intIcon}  className="intermediate-marker">
                    <Popup >
                        <p className="marker-label">{this.state.spot_name + ", " + this.state.county_name}<br/>Wind Speed: {this.state.wind_speed} knots<br/>Difficulty: Intermediate</p>
                    </Popup>
                    </Marker>    
                )
            } else {
                return (
                    <Marker position={[this.state.latitude,this.state.longitude]} icon={expertIcon}  className="expert-marker">
                    <Popup >
                        <p className="marker-label">{this.state.spot_name + ", " + this.state.county_name}<br/>Wind Speed: {this.state.wind_speed} knots<br/>Difficulty: Expert</p>
                    </Popup>
                    </Marker>   
                )
            }
            })()}
            </>
        )
    }

}

我的复选框保存在我的控制面板类中:

import React, { Component } from 'react';
import main from '../styles/main.scss';

export default class ControlPanel extends Component {
    render() {
        return (
            <div className="control-panel">
                <div className="form-check form-check-inline">
                    <input className="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"></input>
                    <label className="form-check-label" htmlFor="inlineCheckbox1">Novice</label>
                </div>

                <div className="form-check form-check-inline">
                <input className="form-check-input" type="checkbox" id="inlineCheckbox2" value="option2"></input>
                <label className="form-check-label" htmlFor="inlineCheckbox2">Intermediate</label>
                </div>

                <div className="form-check form-check-inline">
                <input className="form-check-input" type="checkbox" id="inlineCheckbox3" value="option3"></input>
                <label className="form-check-label" htmlFor="inlineCheckbox3">Expert</label>
                </div>
            </div>
        )
    }
}

我的地图和控制面板都放入了我的仪表板,然后在 App.js 中呈现:

import React, { Component } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import main from '../styles/main.scss'
import SurfMap from './SurfMap.js'
import ControlPanel from './ControlPanel.js';
import Spot from './Spot.js';
import SpotList from './SpotList.js';

export default class Dashboard extends Component {
    render() {
        return (
            <div className="dashboard">
                <div className="dashboard__control-panel">
                    <ControlPanel />
                </div>
                    <SurfMap />
            </div>
        )
    }
}

【问题讨论】:

    标签: javascript reactjs twitter-bootstrap leaflet react-leaflet


    【解决方案1】:

    首先,您需要使用上下文或 redux 存储关卡的状态,因为您希望在没有父子关系的组件之间共享变量。

    这是一种使用上下文的方法。这是您的提供者。它将存储复选框的状态。

    class Provider extends Component {
      state = {
        difficulty: {
          novice: true,
          beginner: true,
          intermediate: false,
          expert: false
        }
      };
    
      setDifficulty = difficulty => {
        this.setState({ difficulty });
      };
    
      render() {
        return (
          <Context.Provider
            value={{
              difficulty: this.state.difficulty,
              setDifficulty: this.setDifficulty
            }}
          >
            {this.props.children}
          </Context.Provider>
        );
      }
    }
    

    然后您想在 ControlPanel 上本地更改关卡状态,完成后更新您的全局上下文:

     class ControlPanel extends Component {
    
          state = { novice: true, beginner: true, intermediate: false, expert: false };
    
          handleInputChange = event => {
            const target = event.target;
            const checked = target.checked;
            const name = target.name;
    
            this.setState({
              [name]: checked
            });
    
            const difficulty = { ...this.state };
            difficulty[name] = checked;
            this.props.setDifficulty(difficulty);
          };
    
          render() {
            const levels = ["novice", "beginner", "intermediate", "expert"];
    
            return (
              <div className="control-panel">
                {levels.map(level => (
                  <div className="form-check form-check-inline">
                    <input
                      className="form-check-input"
                      type="checkbox"
                      name={level}
                      checked={this.state[level]}
                      onChange={this.handleInputChange}
                    />
                    <label className="form-check-label" htmlFor="inlineCheckbox1">
                      {level}
                    </label>
                  </div>
                ))}
              </div>
            );
          }
        }
    
        export default props => (
          <Context.Consumer>
            {({ setDifficulty }) => (
              <ControlPanel {...props} setDifficulty={setDifficulty} />
            )}
          </Context.Consumer>
        );
    

    在 SurfMap 上使上下文可用:

    ....
    
     <>
        <Context.Consumer>
                {({ difficulty }) =>
                  this.state.spots.map((
                    spot,
                    spotIndex //LOOP THROUGH THE LIST OF SPOTS AND CREATE A SPOT FOR EACH ONE TO BE PLOTTED ONTO THE MAP
                  ) => (
                    <Spot key={spotIndex} {...spot} difficulty={difficulty} />
                  ))
                }
              </Context.Consumer>
            </>
    
    ...
    

    终于在Spot comp 使用适当的条件来有条件地呈现标记。 fi if wind_speed is wind_speed is

        ....
            render() {
            const { spot_name, county_name, wind_speed } = this.state;
            const {
              difficulty: { novice, beginner, intermediate, expert }
            } = this.props;
    
            const marker = (
              <Marker
                position={[this.state.latitude, this.state.longitude]}
                icon={beginnerIcon}
                className="beginner-marker"
              >
                <Popup>
                  <p className="marker-label">
                    {spot_name + ", " + county_name}
                    <br />
                    Wind Speed: {wind_speed} knots
                    <br />
                    Difficulty:
                    {wind_speed < 4.2
                      ? "Novice"
                      : wind_speed < 8
                      ? "Beginner"
                      : wind_speed > 8
                      ? "Intermediate"
                      : "Expert"}
                  </p>
                </Popup>
              </Marker>
            );
    
            if (novice && !beginner) return wind_speed < 4.2 && marker;
            else if (!novice && beginner)
              return wind_speed >= 4.2 && wind_speed < 8 && marker;
            else if (novice && beginner) return wind_speed < 8 && marker;
            return null;
          }
    ...
    

    Demo

    【讨论】:

      【解决方案2】:

      如果您想动态更改标记,则必须在标记 json 上设置一个标志,因此如果用户按下复选框,您只需使用从复选框获取的标志重新渲染标记 json。

      【讨论】:

      • 嗯,我不确定这将如何工作。当然,检查哪些复选框被选中并从列表中删除这些标记比向 JSON 文件中添加更多信息更容易吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多