Vue でカスタム ウィジェットを作成

Document created by shinji_katayaesrij-esridist Employee on Oct 14, 2020Last modified by shinji_katayaesrij-esridist Employee on Oct 15, 2020
Version 6Show Document
  • View in full screen mode

はじめに

ArcGIS API for JavaScript はReact, Angular, Vueなどの、JavaScriptのフレームワークと統合して利用することができ、その解説はAPI リファレンスの Using the ArcGIS API for JavaScript with Frameworks に記載されています。

また、以前に紹介した@arcgis/cli を使って、React、Vue のアプリケーションのテンプレートを作成できるほか、[Samle Code] の [Widgets (Advanced)]にも Using widgets with React や Custom widgets with Vue のサンプルが存在しています。

今回の記事は Custom widgets with Vue のサンプルの解説を翻訳し、少しコードを編集して試してみた記事になります。

Web アプリの開発環境をお持ちでない場合でも、Custom widgets with Vue の sandbox を利用して、該当箇所のコードを少し書換えすることでWeb ブラウザー上で動作を試すことが可能です。

 

 

サンプルの解説

 1. Vue のセットアップ

最初に必要なライブラリをロードします。

<!-- Vue を dojoConfig に package として追加-->
<script>
  window.dojoConfig = {
    packages: [
      {
        name: "vue",
        location: "https://unpkg.com/vue/dist/",
        main: "vue"
      }
    ]
  };
</script>
<!-- Esri JSAPI のロード -->
<script src="https://js.arcgis.com/4.17/"></script>

 

 2. シンプルなマップとビューを作成

シンプルなMap を作成し、MapView もしくは SceneView に追加します。もし、view や基本のマップを作成するのになじみが薄い場合は、次のリソースを参照してください。

const map = new Map({
  basemap: "hybrid",
  ground: "world-elevation"
});

const initialCamera = {
  //日本の座標を指定
  position: [138.673, 33.822, 200000],
  tilt: 45,
  heading: 0
};

const view = new SceneView({
  container: "viewDiv",
  map: map,
  camera: initialCamera
});

 

 3. カスタム Vue コンポーネントを作成

HTML テンプレート とJavaScript のロジック でカスタム Vue コンポーネントを作成します。カスタム Vue コンポーネントに関するより詳細な情報は、Vue のドキュメント をご参照ください。

View のカメラの詳細を表示するには、Vue コンポーネントへcamera プロパティを定義します。そして、ボタンクリック時にCamera をclone し、position とtilt を更新後、ViewのgoTo() メソッドで、更新された場所にアニメーション表示で移動します。

 

 Camera オブジェクトのPosition, Tilt, Heading の解説は、3D camera intro using the ArcGIS API for JavaScript で動画で解説されていますので、なじみが薄い場合は、併せてご参照ください。 

Vue.component("camera-info", {
  props: ["camera"],
  template: [
    "<div>",
    "<h2>Camera の詳細</h2>",
    "<p><strong>機首方位 (Heading)</strong>: {{ camera.heading.toFixed(3) }}</p>",
    "<p><strong>前後の傾き (Tilt)</strong>: {{ camera.tilt.toFixed(3) }}</p>",
    "<p><strong>緯度 (Latitude)</strong>: {{ camera.position.latitude.toFixed(3) }}</p>",
    "<p><strong>経度 (Longitude)</strong>: {{ camera.position.longitude.toFixed(3) }}</p>",
    "<button v-on:click='reset'>Camera のリセット</button>",
    "</div>"
  ].join(""),
  methods: {
    reset: function() {
      var camera = this.camera.clone();
      camera.set({
        position: [138.673, 33.822, 200000],
        tilt: 45
      });
      view.goTo(camera);
    }
  }
});

 

 4.Vue コンポーネントのイニシャライズ

DOM にカスタム要素を追加し、カメラのプロパティをバインディングします。そして、Vue コンポーネントをイニシャライズし、Viewのui として追加します。Vue コンポーネントのカメラの変更や更新を、Viewのカメラでウォッチします。

<div id="info" class="esri-widget">
  <camera-info v-bind:camera="camera"></camera-info>
</div>

 

view.when(function() {
  const info = new Vue({
    el: "#info",
    data: {
      camera: view.camera
    }
  });
  view.ui.add(info.$el, "top-right");
  watchUtils.watch(view, "camera", function() {
    info.camera = view.camera;
  });
});

 

完成版のサンプルコード

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>Custom widgets with Vue | Sample | ArcGIS API for JavaScript 4.17</title>
    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.17/esri/themes/light/main.css"
    />
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

      #info {
        padding: 1em;
      }
    </style>
    <script>
      window.dojoConfig = {
        packages: [
          {
            name: "vue",
            location: "https://unpkg.com/vue/dist/",
            main: "vue"
          }
        ]
      };
    </script>
    <script src="https://js.arcgis.com/4.17/"></script>

    <script>
      require([
        "esri/Map",
        "esri/views/SceneView",
        "esri/core/watchUtils",
        "vue"
      ], function(Map, SceneView, watchUtils, Vue) {
        const map = new Map({
          basemap: "hybrid",
          ground: "world-elevation"
        });

        const initialCamera = {
          //日本の座標を指定
          position: [138.673, 33.822, 200000],
          tilt: 45,
          heading: 0
        };

        const view = new SceneView({
          container: "viewDiv",
          map: map,
          camera: initialCamera
        });

        // Vue コンポーネント を作成
        Vue.component("camera-info", {
          props: ["camera"],
          template: [
            "<div>",
            "<h2>Camera の詳細</h2>",
            "<p><strong>機首方位 (Heading)</strong>: {{ camera.heading.toFixed(3) }}</p>",
            "<p><strong>前後の傾き (Tilt)</strong>: {{ camera.tilt.toFixed(3) }}</p>",
            "<p><strong>緯度 (Latitude)</strong>: {{ camera.position.latitude.toFixed(3) }}</p>",
            "<p><strong>経度 (Longitude)</strong>: {{ camera.position.longitude.toFixed(3) }}</p>",
            "<button v-on:click='reset'>Camera のリセット</button>",
            "</div>"
          ].join(""),
          methods: {
            reset: function() {
              var camera = this.camera.clone();
              camera.set(initialCamera);
              view.goTo(camera);
            }
          }
        });

        view.when(function() {
          const info = new Vue({
            el: "#info",
            data: {
              camera: view.camera
            }
          });
          view.ui.add(info.$el, "top-right");
          watchUtils.watch(view, "camera", function() {
            info.camera = view.camera;
          });
        });
      });
    </script>
  </head>

  <body>
    <div id="info" class="esri-widget">
      <camera-info v-bind:camera="camera"></camera-info>
    </div>
    <div id="viewDiv"></div>
  </body>
</html>

 

関連情報

Attachments

    Outcomes