Hirosaji Tech Blog 🍙

Web開発の記事が多め。絵師支援の記事も少し。

ドラッグ操作だけで位置情報データを編集するツールを作った

データの前処理はいつだって大変です。

例えばこのデータ、何を表しているかわかりますか?

 

{
    "title": "こみっくがーるず",
"place": "新宿三丁目前",
"lng": "139.861979",
"lat": "35.760790"
}

 

作品のタイトル(title)と場所(place)、そして緯度経度(longitude, latitude)があることから、勘のいい人は「聖地の場所を表すデータだ」と気が付くかもしれません。

 

では次に、このデータは"正しい"データでしょうか?

 

確かに『こみっくがーるず』には、登場キャラクターが新宿三丁目を練り歩くシーンがあります。

ただ、場所の詳細度が低く、『新宿三丁目前』がどこを指しているのか具体的には分かりません。

 

東京メトロ新宿三丁目」駅前?

それとも、都バス「新宿三丁目」停留所前?

 

考えていても埒があかないので、緯度経度をもとに地図上で確認してみましょう。

 

f:id:hirosaji:20190127231704p:plain

新宿三丁目前の位置情報(NAVITIMEより)

 

んんん???

新宿区でなく、葛飾区の新宿三丁目???

 

調べてみると、葛飾区にも新宿(にいじゅく)*という地名があるとのこと。

そして、残念ながら『こみっくがーるず』には葛飾区が描かれていません。

つまり上記のデータは、文脈上の緯度経度が間違っていました。

 

こんなことが位置情報データの前処理段階で時々起こります。(多くが単純なヒューマンエラーや、Geocodingでの変換が不安定なことが原因)

 

さて、ここで問題なのは、「地図上にプロットするまでデータが正しいかどうか確認できないこと」です。

正直、データをいちいち地図上にプロットして、間違いを見つけては「正しい緯度経度を探してデータを書き換える」なんてことを繰り返すのはとても大変です。

 

それなら、地図上のUIで直接編集できるようにすればいいのでは?

と思い至り、早速デモを作ってみました。

 

デモ

f:id:hirosaji:20190127233025p:plain
DEMO: Leaflet.js × D3.js - location data fix on GUI - bl.ocks.org

 

上記のデモでは、ドラッグ操作だけで直感的にデータを編集できるようになっています。

 

具体的には、位置情報を示すCircle要素をドラッグで動かした分だけデータが書き換わるような仕組みです。(修正後のデータはExportボタンでDL可能)

 

実装コード

Circle要素にドラッグイベントを付与する実装は、Leaflet.jsをちょっと弄ればできました。

ポイントとしては、Circle要素をドラッグしている間は他のドラッグイベントを止め、Cicle要素のドラッグイベントのみが動作するようにすることです。

 

例えば、Circle要素の一つにドラッグイベントを与えるのは、以下の通りです。(Leaflet.jsを事前に読み込んであることが前提)

 

// set map object
var map = L.map('map').setView([35.6915, 139.7015], 16);

// set circle object
var location = [circle_lat, circle_lng];
var option = { radius: 10, color: 'red', opacity: 1, fillColor: 'red', fillOpacity: .4 };
var circle = L.circle(location, option);

// drag & drop event
circle.on('mousedown', function (event) {
    map.dragging.disable();

    var circleStartingLat = circle._latlng.lat;
    var circleStartingLng = circle._latlng.lng;

    var mouseStartingLat = event.latlng.lat;
    var mouseStartingLng = event.latlng.lng;

    map.on('mousemove', e => {
        var mouseNewLat = e.latlng.lat;
        var mouseNewLng = e.latlng.lng;

        var latDifference = mouseStartingLat - mouseNewLat;
        var lngDifference = mouseStartingLng - mouseNewLng;

        var center = [circleStartingLat - latDifference, circleStartingLng - lngDifference];

        circle.setLatLng(center);
    });

    map.on('mouseup', function() {
        map.dragging.enable();
        map.removeEventListener('mousemove');
    });
});

 

ちなみにデモの全コードはbl.ocksに載せていますので、気になる方は以下のリンクを参照してください。

bl.ocks.org

 

また、今回載せたツールを使って芳文社作品の聖地巡礼マップを作っています。興味のある方はぜひ!

hirosaji.github.io