血と汗となみだを流す

個人の思ったこと、やったことの吐き出し口です。

Javascriptがわからないのを克服していく④(地図上の位置情報を取得してオブジェクトを移動する)

概要

対象

  • 実際に公開するページ(ride.html)で動く以下Javascript
    • js/esri-map.js
  • インラインでコメントしながら理解する

js/esri-map.js

  • 地図上でピンやUnicorn画像を動かすための処理
  • Tokenなどの処理はなかった

全体

/*global WildRydes _config*/

// グローバル変数「WildRydes」を定義。定義済みだったら定義済みの変数を使う
var WildRydes = window.WildRydes || {};

// 「WildRydes」のmapオブジェクトを定義。こちらも同じく定義済みだったら定義済みの変数を使う
WildRydes.map = WildRydes.map || {};

// ()でくくってあるので、読み込みと同時に実行される即時関数
(function esriMapScopeWrapper($) {
    ...
}(jQuery));

require.js

    // esriのモジュールをrequireして、requireCallback()を実行する
    require([
        'esri/Map',
        'esri/views/MapView',
        'esri/Graphic',
        'esri/geometry/Point',
        'esri/symbols/TextSymbol',
        'esri/symbols/PictureMarkerSymbol',
        'esri/geometry/support/webMercatorUtils',
        'dojo/domReady!'
    ], function requireCallback(
        ...
    ) {
        ...
    });

requireCallback()

  • 地図上の位置情報を取得して、ピンやUnicorn画像を移動させる処理
function requireCallback(
        // 引数はrequireしたオブジェクト達
        Map, MapView,
        Graphic, Point, TextSymbol,
        PictureMarkerSymbol, webMercatorUtils
    ) {
        // グローバル変数のmapオブジェクト
        var wrMap = WildRydes.map;

        // 「gray-vector」っていうフリーのマップを使ってmapオブジェクト生成
        var map = new Map({ basemap: 'gray-vector' });

        // 地図表示用オブジェクト生成
        var view = new MapView({
            center: [-122.31, 47.60],
            container: 'map',
            map: map,
            zoom: 12
        });

        // 地図上に配置するピンのオブジェクト生成
        var pinSymbol = new TextSymbol({
            color: '#f50856',
            text: '\ue61d',
            font: {
                size: 20,
                family: 'CalciteWebCoreIcons'
            }
        });

        // ピンに向かってくるUnicornのオブジェクト生成
        var unicornSymbol = new PictureMarkerSymbol({
            url: 'images/unicorn-icon.png',
            width: '25px',
            height: '25px'
        });

        var pinGraphic;
        var unicornGraphic;

        // 与えられた緯度経度を地図の中心に持ってくる
        function updateCenter(newValue) {
            wrMap.center = {
                latitude: newValue.latitude,
                longitude: newValue.longitude
            };
        }

        // 与えられた数値を基に、表示領域の更新
        function updateExtent(newValue) {
            var min = webMercatorUtils.xyToLngLat(newValue.xmin, newValue.ymin);
            var max = webMercatorUtils.xyToLngLat(newValue.xmax, newValue.ymax);
            wrMap.extent = {
                minLng: min[0],
                minLat: min[1],
                maxLng: max[0],
                maxLat: max[1]
            };
        }

        // 地図を表示
        view.watch('extent', updateExtent);
        view.watch('center', updateCenter);
        view.then(function onViewLoad() {
            updateExtent(view.extent);
            updateCenter(view.center);
        });

        // 地図上でクリックされたら、eventを取得してhandleViewClick()を実行
        view.on('click', function handleViewClick(event) {

            // 地図上のクリックした地点を取得
            wrMap.selectedPoint = event.mapPoint;

            // ピンを削除
            view.graphics.remove(pinGraphic);

            // クリックした地点に新しいピンを生成
            pinGraphic = new Graphic({
                symbol: pinSymbol,
                geometry: wrMap.selectedPoint
            });

            // 地図に新しいピンを追加
            view.graphics.add(pinGraphic);

            // 「pickupCahge」eventを発生させる
            // event発生時の処理はride.jsのhandlePickupChanged()
            $(wrMap).trigger('pickupChange');
        });

        // アニメーション関数オブジェクト生成
        wrMap.animate = function animate(origin, dest, callback) {
            // 開始時刻
            var startTime;

            // animateFrame()関数を変数に入れる
            var step = function animateFrame(timestamp) {
                var progress;
                var progressPct;
                var point;
                var deltaLat;
                var deltaLon;

                // 開始時刻がなければ現在時刻を設定
                if (!startTime) startTime = timestamp;

                // 経過時間
                progress = timestamp - startTime;

                // 「経過時間/2000」と「1」の小さい方
                progressPct = Math.min(progress / 2000, 1);

                // 移動先と現在地の緯度経度の差分に上記計算したprogressPctを乗算
                deltaLat = (dest.latitude - origin.latitude) * progressPct;
                deltaLon = (dest.longitude - origin.longitude) * progressPct;

                // 移動先の地点のオブジェクトを生成
                point = new Point({
                    longitude: origin.longitude + deltaLon,
                    latitude: origin.latitude + deltaLat
                });

                // Unicorn画像情報を削除
                view.graphics.remove(unicornGraphic);

                // 新しい位置情報を持ったUnicorn画像を生成
                unicornGraphic = new Graphic({
                    geometry: point,
                    symbol: unicornSymbol
                });

                // Unicorn画像を追加
                view.graphics.add(unicornGraphic);

                // progressPctが1以下の場合、ブラウザ上でアニメーションを行う
                // @see https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame
                if (progressPct < 1) {
                    requestAnimationFrame(step);
                } else {
                    callback();
                }
            };
            // ブラウザ上でアニメーションを行う
            requestAnimationFrame(step);
        };

        // 位置情報が設定されていない場合、ピンを削除
        wrMap.unsetLocation = function unsetLocation() {
            view.graphics.remove(pinGraphic);
        };
    }

参考にさせてもらったページ

今回の収穫

プライバシーポリシー