okashi
@okashi (oyatsu daisuki)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Reactとmapbox-glのマーカーにポップアップを表示したい。

Q&A

Closed

ReactもMapboxも初心者です。
React と Mapbox GL JS を使ってベクトルタイルを表示するを参考に、サンプルの通りに作るとちゃんと地図が表示されましたが、App.jsを少し書き換えマーカーと、ポップアップを出すことを試みました。

マーカーにポップアップを表示する時に、緯度経度を直接書き込むと表示できるのですが、下記のようにe.lngLatを入れるとエラーが出てどうしたらいいかわからず。もう一つよくわからないことがあったので下記に質問させていただきます。アドバイス頂けたら助かります。

質問1 .setLngLat(e.lngLat)の設定の仕方

.setLngLat(e.lngLat)

実行すると下記のエラーがでた:

Failed to compile
./src/App.js
  Line 92:16:  'e' is not defined  no-undef

質問2 ...の意味がわからない

コードの中のonClick中で、...prevStyle,という部分があり、この
「...」の意味がわからず、、これも教えていただけたら助かります。

onClick = () => {
    const prevStyle = this.state.style
    const nextStyle = {
      ...prevStyle,
src/App.js
import React, { Component } from 'react'
import mapboxgl from 'mapbox-gl'
import './App.css'
import 'mapbox-gl/dist/mapbox-gl.css'

const BASE_URL = 'https://api.mapbox.com/styles/v1/mapbox/streets-v9'//ここにはJSONが入っている

class App extends Component {
  constructor(props) {
    super(props)
    this.state = { style: false }
  }
  componentDidMount = async () => {
    const url = `${BASE_URL}?access_token=${mapboxgl.accessToken}`//URLにはJSONが入っている
    const style = await fetch(url).then(res => res.json())//コードの実行は先に進まない
//非同期でfetchに入ったJsonは地図のタイル
    this.map = new mapboxgl.Map({
      container: this.container,
      center: [138, 36.0],
      zoom: 13,
      style,
    });

  //普通のマーカー
  var marker = new mapboxgl.Marker()
    .setLngLat([138, 36.0])
    .addTo(this.map);

  //popup .setLngLat(e.lngLat)のeでエラーが出る
  var markerHeight = 50, markerRadius = 10, linearOffset = 25;
  var popupOffsets = {
  'top': [0, 0],
  'top-left': [0,0],
  'top-right': [0,0],
  'bottom': [0, -markerHeight],
  'bottom-left': [linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
  'bottom-right': [-linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
  'left': [markerRadius, (markerHeight - markerRadius) * -1],
  'right': [-markerRadius, (markerHeight - markerRadius) * -1]
  };
  var popup = new mapboxgl.Popup({offset: popupOffsets, className: 'my-class'})
  //  .setLngLat([138, 36.0]) だと普通に表示される
    .setLngLat(e.lngLat)
    .setHTML("<h1>Hello World!</h1>")
    .setMaxWidth("300px")
    .addTo(this.map);

    this.setState({ style })
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.style !== this.state.style) {
      this.map.setStyle(this.state.style)
    }
  }
  componentWillUnmount() {
    this.map.remove()
  }

  onClick = () => {
    const prevStyle = this.state.style
    const nextStyle = {
      ...prevStyle,
      layers: prevStyle.layers.map(
        layer =>
          layer.id === 'landcover_snow'
            ? { ...layer, paint: { ...layer.paint, 'fill-color': 'red' } }
            : layer,
      ),
    }
    this.setState({ style: nextStyle })
  }

  render() {
    return (
      <div className={'map'} ref={e => (this.container = e)}>
        <button
          style={{ position: 'absolute', zIndex: 1 }}
          onClick={this.onClick}
        >
          {'氷雪地帯は?'}
        </button>
      </div>
    )
  }}

export default App

@chromia さんに教えていただいた Attach a popup to a marker instanceをみて、なんとかポップアップがでるところまではできました。

src/App.js
// src/App.js
import React, { Component } from 'react'
import mapboxgl from 'mapbox-gl'
import './App.css'
import 'mapbox-gl/dist/mapbox-gl.css'

const BASE_URL = 'https://api.mapbox.com/styles/v1/mapbox/streets-v9'//ここにはJSONが入っている

class App extends Component {
  constructor(props) {
    super(props)
    this.state = { style: false}//--:--,ここに付け足して行けばいい?
  }

  componentDidMount = async () => {//ここで地図の描画をする async

    const url = `${BASE_URL}?access_token=${mapboxgl.accessToken}`//URLにはJSONが入っている
    const style = await fetch(url).then(res => res.json())//コードの実行は先に進まない

//非同期でfetchに入ったJsonは地図のタイル
    this.map = new mapboxgl.Map({
      container: this.container,
      center: [138, 36.0],
      zoom: 13,
      style,
    });

  // create the popup
var popup = new mapboxgl.Popup({ offset: 25 }).setText(
'Popup Comment.'
);

// create DOM element for the marker
var el = document.createElement('div');
el.id = 'marker';

  //普通のマーカーは立てることができた
  var marker = new mapboxgl.Marker()
    .setLngLat([138, 36.0])
    .setPopup(popup)
    .addTo(this.map);
    this.setState({ style })
  }//ここで地図の描画をする?end

  componentDidUpdate(prevProps, prevState) {
//styleしか渡してないから、markerとpopupも渡せるようにしたい

    if (prevState.style !== this.state.style) {
      this.map.setStyle(this.state.style)
    }
  }

  componentWillUnmount() {
    this.map.remove()
  }

  onClick = () => {
    const prevStyle = this.state.style
    const nextStyle = {
      ...prevStyle,
      layers: prevStyle.layers.map(
        layer =>
          layer.id === 'landcover_snow'
            ? { ...layer, paint: { ...layer.paint, 'fill-color': 'red' } }
            : layer,
      ),
    }
    this.setState({ style: nextStyle })
  }

  render() {
    return (
      <div className={'map'} ref={e => (this.container = e)}>
        <button
          style={{ position: 'absolute', zIndex: 1 }}
          onClick={this.onClick}
        >
          {'氷雪地帯は?'}
        </button>

      </div>
    )
  }
}

export default App


やや進化

// this.map.on('load', function() {//これだとthisが別のものを指す
// https://stackoverflow.com/questions/47970880/add-geojson-to-this-map-mapbox-gl-js
     this.map.on('load', () =>{

//アロー関数だと内部で指定していない場合はグローバル?と同じthisを指す。画面がloadされたらmapもonになる

0

2Answer

変数eが定義されていないのでエラーが出ています。どこからソースコードをコピーしてきたかはわかりませんが、クリックしたときのイベントか何かで引数にeが渡されていたのではありませんか?
ポップアップって大体マーカーとかをクリックした場合に出すものなので、マーカーのクリックイベントを定義して、その中でポップアップを生成すればいいんじゃないでしょうか(あてずっぽうですけども)。

...はスプレッド構文というやつです。
配列あるいはオブジェクトの中身を、ベタ書きしたかのように展開してくれるものです

1Like

Comments

  1. @okashi

    Questioner

    @chromia さん、回答をありがとうございます。

    > クリックしたときのイベントか何かで引数にeが渡されていたのではありませんか?

    マーカーがクリックされるとPopupが動的に表示させるにはどうしたらいいか考え、
    付け加えたのですが実際には動かせていません。

    ```js

    .setLngLat(e.lngLat);

    ```

    下記のように直に緯度経度を入れるとPopup表示はされたのですが、
    動的にするにはということを
    まだ解決できていないので、イベントについてもう少し勉強しなくては、、という感じです。

    ```js

    .setLngLat([138, 36.0]);

    ```

    > ...はスプレッド構文というやつです。

    ありがとうございます!

Comments

  1. @okashi

    Questioner

    @chromia さん、ありがとうございます。
    やはりエンジニアさんは調べる能力が高いですね!
    自分もそうなれるようにしたい、しかしどうしたらその修行を積めるんだろうか、、と思いました。

    また、教えていただいた [Attach a popup to a marker instance](https://docs.mapbox.com/mapbox-gl-js/example/set-popup/) を参考にしたら、とりあえずクリックすると出てくるポップアップは実現することができました。本文の方に追記します。ありがとうございます。

Your answer might help someone💌