フェニックスでGoogleマップを使う方法


この記事は我々のCEOと開発者によって書かれた
ディアリーダー🖖🏽, あなたがこれらの困った時代の間、安全で健康であるという望み.
過去3年間、我々はfew projects 使用Phoenix Framework for Elixir . そしてすぐにLiveView が発表された、我々はそれを使用するのを待つことができなかった!
我々は、LiveViewを使用してプラットフォームを構築している多くの意味を作ったので、我々はいくつかの機能をリアルタイムで更新することができるインターフェイスを使用したい.たとえば、我々は、プラットフォームの管理者は、地図上では、アプリのユーザーが特定の場所に報告していた目撃者は、彼らが起こるように見ることができるようにしたい.それをライブマップと呼びましょう.

技術の理解🤓


問題を掘る前に、我々が使用している技術を見てみましょう.我々は、あなたがエリクサーとフェニックスに精通していると仮定しています.

フェニックス


によるとdocumentation :

LiveView provides rich, real-time user experiences with server-rendered HTML.
The LiveView programming model is declarative: instead of saying “once event X happens, change Y on the page”, events in LiveView are regular messages which may cause changes to its state.
Once the state changes, LiveView will re-render the relevant parts of its HTML template and push it to the browser, (…) LiveView does the hard work of tracking changes and sending the relevant diffs to the browser.


グーグルマップ


ドキュメントによると、

The Maps JavaScript API lets you customise maps with your own content and imagery for display on web pages and mobile devices.


シドニーを中心とした地図が表示されるページがあるので、次のようにする必要があります.
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script>
      (function(exports) {
        "use strict";

        function initMap() {
          exports.map = new google.maps.Map(document.getElementById("map"), {
            center: {
              lat: -34.397,
              lng: 150.644
            },
            zoom: 8
          });
        }

        exports.initMap = initMap;
      })((this.window = this.window || {}));
    </script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>

チャレンジ🤔


私たちのライブマップでは、静的な地図を表示するよりも少しだけ必要があります.我々はまた、ユーザーが目撃を報告している場所を示すマーカーを表示するマップが必要になります.
また、マーカーは、ユーザーが報告するとすぐに表示する必要があります🤯. あなたは、考えているかもしれません:「よく、我々は簡単になければなりません.それを試してみて、自分で見ましょう.

解決策💡


我々は準備したrepository あなたが使用することができますし、自分のためのボイラープレートを行うことを避けるために、記事の特定の部分にジャンプします.

初期設定


The initial setup プロジェクトを自動的に生成します.
私たちは--no-ecto オプションは、我々が必要になりませんプロジェクトを生成するときEcto .

LiveViewページにマップを追加する


我々simply added the HTML + CSS + JS アップロードするGoogleマップのセクションで説明したコード.
どうぞ忘れないでくださいhere あなたGoogle Maps API key あなたがそれが働くのを見たいならば、プロジェクトに.
プロジェクトを実行するならmix phx.server ), あなたはマップが短い瞬間、右後に消えて表示されます.地図はどこへ行ったのですか.🤔

LiveViewページに地図をつける


我々の問題を理解するためには、まずlife-cycle of a LiveView :

A LiveView begins as a regular HTTP request and HTML response, and then upgrades to a stateful view on client connect, guaranteeing a regular HTML page even if JavaScript is disabled. Any time a stateful view changes or updates its socket assigns, it is automatically re-rendered and the updates are pushed to the client.
(…)
After rendering the static page, LiveView connects from the client to the server where stateful views are spawned to push rendered updates to the browser, and receive client events via phx- bindings. Just like the first rendering, mount/3 is invoked with params, session, and socket state, where mount assigns values for rendering.


あなたがトピックに深く行きたいならば、LiveViewのinnersがどのように働くかについて、よく説明してください.
私たちの場合、何が起こっているのでしょうか
  • 初期ページレンダリングがあります
  • Google Mapsスクリプトが読み込まれ、我々の呼び出しinitMap 機能
  • The initMap 関数はマップを初期化する.これはdivid="map" マップを表すすべての必要なマークアップで満たされる
  • 同時に、Webページはサーバー上のLiveViewに接続します.とドキュメントの状態として:“最初のレンダリングと同じように.mount/3 はparams、session、socketの状態で起動されます.
  • ブラウザー側のLiveView(JavaScript)は、次に、何がHTMLでなければならないか、そして、それが現在何であるかの拡散をします
  • そして驚き、驚き🎁 ! 現在のHTMLには、マップのマークダウンが含まれています.これはページが最初にレンダリングされたときには存在しませんでした.このようなクライアント側のLiveViewは、その変更を😭
  • 良い部分は、LiveViewのクリエイターがこれらのケースについて考えて、あなたに可能性を与えるということですcontrol the patching mechanism :

    A container can be marked with phx-update, allowing the DOM patch operations to avoid updating or removing portions of the LiveView, or to append or prepend the updates rather than replacing the existing contents. This is useful for client-side interop with existing libraries that do their own DOM operations.
    (…)
    The “ignore” behaviour is frequently used when you need to integrate with another JS library.


    実際的にはwe only need to add エーphx-update="ignore" マップコンテナにLiveViewに、そのコンテナーの内容がコントロールされていることを通知します.
    次の結果が表示されます.

    d :サーバから要素を動的にプッシュする方法


    最後のステップだけが不足している:目撃者はすぐにユーザーが報告するように表示する必要があります.
    ユーザーによって報告されているため息をシミュレートするために、データベースに格納されて、それから他のユーザーに放送される.we added a button をランダムに生成する.このボタンは、ユーザーが実際にため息を報告したかのように、イベントをサーバーに送信します.LiveViewは、私たちが新しい照準を持っているブラウザに通知するのを気にします.
    最後の結果は次のようになります.

    重要な部分をまとめる.what we did was:
    クリエイトAjavascript hook
    Hooks.MapSightingsHandler = {
      mounted() {
        const handleNewSightingFunction = ({ sighting }) => {
          var markerPosition = { lat: sighting.latitude, lng: sighting.longitude };
    
          const marker = new google.maps.Marker({
            position: markerPosition,
            animation: google.maps.Animation.DROP,
          });
    
          // To add the marker to the map, call setMap();
          marker.setMap(window.map);
        };
    
        // handle new sightings as they show up
        this.handleEvent('new_sighting', handleNewSightingFunction);
      },
    };
    
    let csrfToken = document
      .querySelector("meta[name='csrf-token']")
      .getAttribute('content');
    let liveSocket = new LiveSocket('/live', Socket, {
      hooks: Hooks,
      params: { _csrf_token: csrfToken },
    });
    
    新しく追加しましたhandleEvent / pushEvent フックの特徴.このメソッドはLiveView version 0.14 :

    The hook can push events to the LiveView by using the pushEvent function and receive a reply from the server via a {:reply, map, socket} return value. The reply payload will be passed to the optional pushEvent response callback.
    Communication with the hook from the server can be done by reading data attributes on the hook element, or by using push_event on the server and handleEvent on the client.


    マップマークアップにJavaScriptフックを使用する
    新しく作成されたフックを使用/添付するには、次の手順を実行しなければなりませんでした.
    <section class="row" phx-update="ignore" phx-hook="MapSightingsHandler">
    
    要素がマウントされるとすぐに、LiveView genserverは名前でイベントをプッシュしますnew_sighting , the handleEvent コールバックがトリガされ、マップマーカーが追加されます.
    イベント/目撃をプッシュするLiveViewのgenserverを更新します
    実際に注文を受信するサーバー部分は、Aによって送信されたイベントを介して、ランダムな照準を作成しますphx-click=”add_random_sighting”button シミュレーションのために、イベントをブラウザのソケットにプッシュします.
    defmodule LiveViewGoogleMapsWeb.PageLive do
      use LiveViewGoogleMapsWeb, :live_view
    
      @impl true
      def mount(_params, _session, socket) do
        {:ok, socket}
      end
    
      @impl true
      def handle_event("add_random_sighting", _params, socket) do
        random_sighting = generate_random_sighting()
    
        # inform the browser / client that there is a new sighting
        {:noreply, push_event(socket, "new_sighting", %{sighting: random_sighting})}
      end
    
      defp generate_random_sighting() do
        # https://developers.google.com/maps/documentation/javascript/reference/coordinates
        # Latitude ranges between -90 and 90 degrees, inclusive.
        # Longitude ranges between -180 and 180 degrees, inclusive
        %{
          latitude: Enum.random(-90..90),
          longitude: Enum.random(-180..180)
        }
      end
    end
    
    あなたがすべてを適用するならばchanges そして、あなたは現在ランダムにあなたの地図のマーカーを作成することができるコードを実行します.

    改善👆🏾


    私たちはその記事を話題に集中させるためにいくつかのコーナーを切り取らなければならなかった.
    別の記事にはおそらくいくつかの点があります.
    どのように地図上で既に格納されて目撃を表示するには?
    つは、これは非常に簡単に思えるかもしれないmount 我々は/スケジュールを送信することができますpushEvent !”.
    ここでの問題点は、GoogleマップスクリプトがpushEvent . スクリプトが読み込まれた場合、handleEvent マーカーを作成する関数は、マップへのアクセスを持っていないように、それは失敗し、マーカーをレンダリングされません!
    正しく保存し、目撃の作成、更新、削除を放送?
    我々は、目撃の追加を扱うだけでなく、データベースにそれらを格納しないか、すべてのユーザーに放送します.
    どのように、新しい目撃を受けて、データベースにそれを保存して、そして、この情報をすべてのユーザーに放送するでしょうか?
    どのようにより良い構造のコード?
    記事を集中させるために、もう一度、我々は最短の解決のために行って、テクノロジー自体に集中することに決めました.
    例えば、我々は露出しているmap フックにオブジェクトを直接追加しますwindow . してくださいこれで生産を行う!
    お気軽に問題に言及し、あなたの提案のソリューションとプルの要求を行うに取り組む.私たちはあなたからも学ぶことが非常に幸せになる!👩🏾‍🎓

    結論


    我々は非常に我々はLiveViewで達成しているソリューションと結果に満足している.他のツールと同様に、それ自身のものを持っていることに留意してくださいuse cases そして、あなたは最初にそれをコミットする前にあなたが持っている問題を理解しなければなりません.
    我々がまだLiveViewに持っている最大の欠点はコード構造化/組織です.我々はまだ100 %自信を持っている構造を発見していないので、我々はそこに着くまで繰り返して続けている.
    コミュニティは既にこのための解決策に取り組んでおり、既にライブラリがありますsurface それがこの問題に取り組む.表面は私たちの“テスト/研究/学習”のリストにあり、我々は確かにそれを試してみる.
    また、LiveViewはまだアルファステージです.変更を伴う新しいリリースが利用できるように、我々はかなり依存性をアップグレードし続けなければなりません.これの明るい面は、それがすべての新しいリリースでより良くなっているということです!🥇

    読んでくれてありがとう!


    読書ありがとうございます、それは私たちに多くを意味する!また、フォローすることを忘れないでください、我々は複数の技術上でより興味深い記事を投稿し続ける.
    あなたが知らない場合は、coletivはポルトからエリクソン、Web、およびアプリケーション(IOS&Android)の開発に特化されたソフトウェア開発スタジオです.しかし、我々はあらゆる種類のものをします.私たちはUX/UIの設計、ソフトウェア開発、さらにはあなたのためのセキュリティの世話をする.
    それでlet’s craft something together?