LoginSignup
twtjudy1128
@twtjudy1128 (Juri Tawata)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

LINEbotで現在地情報を送ったら、近くのスポットを返すコードを書きたい【Javascript/Node.js】

作りたいもの

LINEbotで現在地情報を送ったら、近くのスポットをlocationで返すようにしたいです。

Node.jsでコードを書いていて、ソースコード内にスポットの全データをオブジェクトとして入れ込んでいます。

そのデータの中から、取得した位置情報をもとにスポットを抽出したいのですが、
距離の測り方と、該当するデータの取得方法がわかりません。

どなたかヒントをいただけませんでしょうか。
宜しくお願いします。

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

    //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
    if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello LINE BOT!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

const data = [
    { lon: 139.768936, lat: 35.696804, spot: '竹むら', address: '東京都千代田区神田須田町1丁目19', memo: '穂乃果の実家!和菓子食べたい!', category: 'ラブライブ!' },
    { lon: 139.768295, lat: 35.696037, spot: '昌平橋', address: '東京都千代田区神田須田町1丁目1−1', memo: 'よくみんなが集まるあの橋だよ!', category: 'ラブライブ!' },
    { lon: 139.771545, lat: 35.698414, spot: '秋葉原ゲーマーズ本店前', address: '東京都千代田区外神田1丁目14−7', memo: '海未ちゃんがビラ配りしてるかも…!', category: 'ラブライブ!' },
    { lon: 139.772568, lat: 35.700584, spot: '秋葉原UDX前', address: '東東京都千代田区外神田4丁目14−1', memo: '画面を見上げるとA-RISEが出てこないかとドキドキします。', category: 'ラブライブ!' },
    { lon: 139.767715, lat: 35.702129, spot: '神田明神', address: '東京都千代田区外神田2丁目16−2', memo: 'ラブライバーにはお馴染み!男坂を駆け上がり、希ちゃんに会いに行こう!', category: 'ラブライブ!' },
    { lon: 139.772568, lat: 35.700584, spot: '肉のハナマサ前', address: '東京都千代田区外神田4丁目14−1', memo: 'ニコちゃんを捕まえろ!', category: 'ラブライブ!' },
    { lon: 139.770889, lat: 35.699974, spot: '住友不動産秋葉原ビル西側', address: '東京都千代田区外神田3-12-8', memo: 'ニコちゃんを捕まえろ!Part2!', category: 'ラブライブ!' },
    { lon: 139.768799, lat: 35.697632, spot: '神田郵便局前交差点', address: '東京都千代田区神田淡路町2ー12', memo: 'エリーチカとのんたんの友情', category: 'ラブライブ!' },
    { lon: 139.765167, lat: 35.698803, spot: 'お茶の水サンクレール', address: '東京都千代田区神田駿河台4丁目3', memo: '1年生が集まっていたところ!尊い!', category: 'ラブライブ!' },
    { lon: 139.771301, lat: 35.701672, spot: 'アキバ系アイドルショップ', address: '東京都千代田区大手町1丁目9', memo: 'アニメ内では、スクールアイドルショップでした!', category: 'ラブライブ!' },
    { lon: 139.765411, lat: 35.688286, spot: '神田橋', address: '東東京都千代田区外神田4丁目14−1', memo: '全員が合流!ラブライブ会場はもうすぐ!', category: 'ラブライブ!' },
    { lon: 139.762222, lat: 35.680233, spot: '行幸通り', address: '東京都千代田区丸の内2丁目2', memo: '名曲!スノハレ聖地!ウルトラオレンジを持って歩こう!', category: 'ラブライブ!' },
    { lon: 139.763245, lat: 35.698021, spot: '池田坂', address: '東京都千代田区神田駿河台1丁目8−13', memo: 'ラブライブ会場へと続く道!一緒に走ろう!', category: 'ラブライブ!' },
    { lon: 139.700089, lat: 35.659607, spot: 'スクランブル交差点', address: '東京都渋谷区道玄坂2丁目2−1', memo: '人混みをくぐり抜けながらのドリフトは見物!', category: 'ワイスピ' },
    { lon: 139.777008, lat: 35.681942, spot: '日本橋兜町パーキング', address: '東京都中央区日本橋1丁目21', memo: 'ドリフトレース会場!妻夫木を俺は忘れない。', category: 'ワイスピ' },
    { lon: 139.738251, lat: 35.654594, spot: '住宅街', address: '東京都港区三田1-10', memo: 'ショーンのお父さんが住んでたところ!', category: 'ワイスピ' },
  ];



async function handleEvent(event) {
  // 位置情報のみに入力制限
  if (event.type !== 'message' || event.message.type !== 'location') {
    return Promise.resolve(null);
  }
  // 取得した位置情報をログに表示
  console.log(event.message.latitude + ' : ' + event.message.longitude);

  return client.replyMessage(event.replyToken, {
    type: 'location',
    title: 'あいうえお' ,//response.data.rest[hitnum].name,
    address: '東京都中央区日本橋1丁目21' , //response.data.rest[hitnum].address,
    latitude: event.message.latitude ,//response.data.rest[hitnum].latitude,
    longitude: event.message.longitude, //response.data.rest[hitnum].longitude
  });

0

2Answer

Qiitaにjsで距離測るやり方とかありますけど、
どうせならライブラリでさくっとできたら良いですねw

▲このライブラリの「insideCircle」とかどうですかね?
dataオブジェクトがそこまで量無いならループで回せそうかも?

▲最寄りの1件、とかならこちらの「findNearest」とか

1

Comments

  1. @twtjudy1128

    Questioner
    ありがとうございます!こんなライブラリがあるんですね…
    今必死に英語を読み解いてます…!

    イメージは湧いてきたので、具体化できるようにトライしてみます!
    ありがとうございます><

こんな感じでいけそうです。動作確認や数式の検算はしていないのでご自身でチェックお願いします。

// 角度をラジアンに変換
function toRad(deg) {
  return deg / 180 * Math.PI;
}

// 2点間の大円距離を計算(返り値は km 単位)
// 参考: http://www.orsj.or.jp/archive2/or60-12/or60_12_701.pdf
function distance(lat1, lon1, lat2, lon2) {
  lat1 = toRad(lat1);
  lon1 = toRad(lon1);
  lat2 = toRad(lat2);
  lon2 = toRad(lon2);

  return 6370 * Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
}

// 与えた緯度経度の地点からもっとも近い場所を返す
function getNearestLocation(lat, lon) {
  // dataWithDistance は [ [場所1, 指定地点と場所1の距離], [場所2, 指定地点と場所2の距離], ... ]
  let dataWithDistance = data.map(item => [item, distance(lat, lon, item.lat, item.lon)]);

  // 距離がもっとも近い場所を取り出す
  // reduce() の解説: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
  return dataWithDistance.reduce((nearest, current) => current[1] < nearest[1] ? current : nearest)[0] || null;
}

// handleEvent() の中で……
const nearestLocation = getNearestLocation(event.message.latitude, event.message.longitude);

ところで、

そのデータの中から、取得した位置情報をもとにスポットを抽出したいのですが、
距離の測り方と、該当するデータの取得方法がわかりません。

こういうときはやりたいことを一般的な単語に置き換えてそのまま検索すればだいたい手がかりが見つかります。

「 取得した位置情報をもとにスポットを抽出したい」→「2点の経度と緯度から距離を計算したい。距離の中から最小値を見つけたい」

  • 「経度 緯度 距離 計算」で検索
  • 「JavaScript 配列 最小値を求める」で検索
  • Node.js のモジュールを探すなら英語にして 「Node.js latitude longitude distance calculate」とか

自分も距離の計算式は検索で見つけました。

1

Comments

  1. @twtjudy1128

    Questioner
    @uasiさん
    度々、本当にありがとうございます。本当に助かります

    https://gist.github.com/twtjudy1128/85dcabe93734dbc213bcb70de44d2d62

    早速コードを利用させていただきましたが、55行目のlocationでエラーになります。
    オブジェクトでspotを使ってるので、spotに変更してみましたがそれでもエラーになってしまいました。

    どこかで宣言しないといけないでしょうか?
  2. @twtjudy1128

    Questioner
    検索方法もありがとうございます。
    そうですね・・・!プログラミングは何より検索力だと以前伺ったことがあり、今ひしひしと実感しております・・・。

    周りが非エンジニアばかりなので、検索力高めて自走できるよう精進します。
    アドバイス本当にありがとうございます。
  3. @twtjudy1128 さん、 location はミスでした、 item の間違いです。本文を修正しました。
  4. @twtjudy1128

    Questioner
    @uasiさん、ありがとうございます!私も気づけなくて申し訳ございません。
    こちらで無事最寄りスポット出せました!
    lineにlocationで返すとこまでできたので、最低限の実装はできました、ありがとうございます。

    ここからは、教えていただいた検索を駆使して、〆切までにパワーアップさせようと思います!(スクールの宿題なんです。笑)

    本当にありがとうございました。

Your answer might help someone💌