Help us understand the problem. What is going on with this article?

overpassからfetchを使用して、トイレマップを取得したい

はじめに

ReactNativeで地図上にといてを表示したいと思い立ち、
overpassからfetchを使ってトイレ情報を取得しようとしたところ
Status:400になってしまい、取得できないことがあった。

解決したので、同じところでつまづかないようにするためにこの記事を書いていく。

ソース

App.js
import React, { Component } from 'react';
import { StyleSheet ,Text, View,TouchableOpacity} from 'react-native';
import MapView from 'react-native-maps';
import {point } from '@turf/helpers'
import destination from '@turf/destination'

export default class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      elements:[],
      south:null,
      west:null,
      north:null,
      east:null,
    }
  }
  onRegionChangeComplete = (region) =>{
    const center = point([region.longitude,region.latitude])

    const verticalMeter = 111 * region.latitudeDelta / 2
    const horizontalMeter = 111 * region.longitudeDelta / 2


    const options = {units:'kilometers'}
    const south = destination(center,verticalMeter,180,options)
    const west = destination(center,horizontalMeter,-90,options)
    const north = destination(center,verticalMeter,0,options)
    const east = destination(center,horizontalMeter,90,options)

    this.setState({
      south:south.geometry.coordinates[1],
      west:west.geometry.coordinates[0],
      north:north.geometry.coordinates[1],
      east:east.geometry.coordinates[0],
    })
  }
  fetchToilet = async () =>{
    const south = this.state.south
    const west = this.state.west
    const north = this.state.north
    const east = this.state.east
    const body = `out:json;(node(${south},${west},${north},${east})[amenity=toilets];);out;`
    const options = {
      method:'POST',
      body:body,
    }
    try{
      const response = await fetch('https://overpass-api.de/api/interpreter',options)
      if(response.ok){
        const json = await response.json()
        this.setState({elements:json.elements})
      }else{
        console.log('失敗')
      }

    }catch(e){
        console.log(e)
    }
  }
  render() {
    return (
      <View style={styles.container}>
        <MapView
          onRegionChangeComplete={this.onRegionChangeComplete}
          style={styles.map}
          initialRegion={{
            latitude: 35.681262,
            longitude: 139.766403,
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0421,
          }}
        >
          {
            this.state.elements.map((element)=>{
              let title = 'トイレ'
              if(element.tags["name"] !== undifined){
                title  = element.tags["name"]
              }
              return (<MapView.Marker
                coordinate={{
                  latitude:element.lat,
                  longitude:element.lon
                }}
                title={title}
                id={"id_"+element.id}
                />)
            })
          }

        </MapView>
        <View style={styles.buttonContainer}>
          <TouchableOpacity
            onPress={()=>this.fetchToilet()}
            style={styles.button}
            >
              <Text style={styles.buttonItem}>トイレ取得</Text>
            </TouchableOpacity>

        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container:{
    flex:1,
    backgroundColor:'#fff',
    alignItems:'center',
    justifyContent:'center',
  },
  map: { ...StyleSheet.absoluteFillObject, },
  button:{
    width:150,
    alignItems:'center',
    justifyContent:'center',
    backgroundColor:'rgba(255,255,255,0.7)',
    paddingHorizontal:18,
    paddingVertical:12,
    borderRadius:20,

  },
  buttonContainer:{
    flexDirection:'row',
    marginVertical:20,
    backgroundColor:'transparent',
    alignItems:'center',
  },
  buttonItem:{
    textAlign:'center',
  },
});

修正したソース

App.js
import React, { Component } from 'react';
import { StyleSheet ,Text, View,TouchableOpacity} from 'react-native';
import MapView from 'react-native-maps';
import {point } from '@turf/helpers'
import destination from '@turf/destination'

export default class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      elements:[],
      south:null,
      west:null,
      north:null,
      east:null,
    }
  }
  onRegionChangeComplete = (region) =>{
    const center = point([region.longitude,region.latitude])

    const verticalMeter = 111 * region.latitudeDelta / 2
    const horizontalMeter = 111 * region.longitudeDelta / 2


    const options = {units:'kilometers'}
    const south = destination(center,verticalMeter,180,options)
    const west = destination(center,horizontalMeter,-90,options)
    const north = destination(center,verticalMeter,0,options)
    const east = destination(center,horizontalMeter,90,options)

    this.setState({
      south:south.geometry.coordinates[1],
      west:west.geometry.coordinates[0],
      north:north.geometry.coordinates[1],
      east:east.geometry.coordinates[0],
    })
  }
  fetchToilet = async () =>{
    const south = this.state.south
    const west = this.state.west
    const north = this.state.north
    const east = this.state.east
    const body = `[out:json];(node[amenity=toilets](${south},${west},${north},${east}););out;`
    const options = {
      method:'POST',
      body:body,
    }
    try{
      const response = await fetch('https://overpass-api.de/api/interpreter',options)
      if(response.ok){
        const json = await response.json()
        this.setState({elements:json.elements})
      }else{
        console.log('失敗')
      }

    }catch(e){
        console.log(e)
    }
  }
  render() {
    return (
      <View style={styles.container}>
        <MapView
          onRegionChangeComplete={this.onRegionChangeComplete}
          style={styles.map}
          initialRegion={{
            latitude: 35.681262,
            longitude: 139.766403,
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0421,
          }}
        >
          {
            this.state.elements.map((element)=>{
              let title = 'トイレ'
              // if(element.tags["name"] !== undifined){
              //   title  = element.tags["name"]
              // }
              return (<MapView.Marker
                coordinate={{
                  latitude:element.lat,
                  longitude:element.lon
                }}
                title={title}
                id={"id_"+element.id}
                />)
            })
          }

        </MapView>
        <View style={styles.buttonContainer}>
          <TouchableOpacity
            onPress={()=>this.fetchToilet()}
            style={styles.button}
            >
              <Text style={styles.buttonItem}>トイレ取得</Text>
            </TouchableOpacity>

        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container:{
    flex:1,
    backgroundColor:'#fff',
    alignItems:'center',
    justifyContent:'center',
  },
  map: { ...StyleSheet.absoluteFillObject, },
  button:{
    width:150,
    alignItems:'center',
    justifyContent:'center',
    backgroundColor:'rgba(255,255,255,0.7)',
    paddingHorizontal:18,
    paddingVertical:12,
    borderRadius:20,

  },
  buttonContainer:{
    flexDirection:'row',
    marginVertical:20,
    backgroundColor:'transparent',
    alignItems:'center',
  },
  buttonItem:{
    textAlign:'center',
  },
});

修正した箇所を抜き出してみると

修正前

const body = `out:json;(node(${south},${west},${north},${east})[amenity=toilets];);out;`

修正後

const body = `[out:json];(node[amenity=toilets](${south},${west},${north},${east}););out;`

out:jsonを[]でくくっただけ、兎にも角にもトイレが地図上に表示できたのでOKということにしましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした