defmodule LiveMap do
@external_resource "./README.md"
@moduledoc """
#{File.read!(@external_resource)}
"""
require Logger
alias LiveMap.Tile
@doc deletegate_to: {Tile, :map, 5}
defdelegate tiles(latitude, longitude, zoom, width, height), to: Tile, as: :map
@doc deletegate_to: {Tile, :map, 6}
defdelegate tiles(latitude, longitude, zoom, width, height, mapper), to: Tile, as: :map
use Phoenix.LiveComponent
@impl Phoenix.LiveComponent
@spec mount(Phoenix.LiveView.Socket.t()) :: {:ok, Phoenix.LiveView.Socket.t()}
def mount(socket) do
{:ok,
socket
|> assign_new(:width, fn -> 300 end)
|> assign_new(:height, fn -> 150 end)
|> assign_new(:title, fn -> "" end)
}
end
@impl Phoenix.LiveComponent
@spec update(Phoenix.LiveView.Socket.assigns(), Phoenix.LiveView.Socket.t()) ::
{:ok, Phoenix.LiveView.Socket.t()}
def update(assigns, socket) do
width = assigns[:width] || socket.assigns[:width]
height = assigns[:height] || socket.assigns[:height]
latitude = assigns[:latitude] || socket.assigns[:latitude] || 0
longitude = assigns[:longitude] || socket.assigns[:longitude] || 0
zoom = assigns[:zoom] || socket.assigns[:zoom] || 0
center = Tile.at(latitude, longitude, zoom)
tiles = Tile.map(center, width, height)
{:ok,
socket
|> assign(assigns)
|> assign(:zoom, zoom)
|> assign(:tiles, tiles)
}
end
# @callback render/1 is handled by `Phoenix.LiveView.Renderer.before_compile`
# by looking for a ".html" file with the same name as this module.
@doc """
Returns the viewbox that covers the tiles.
This essentially starts from the top left tile, and ends at the bottom right tile.
Examples:
iex> LiveMap.viewbox([])
"0 0 0 0"
iex> LiveMap.viewbox([%{x: 0, y: 0}])
"0 0 1 1"
iex> LiveMap.viewbox([
...> %{x: 0, y: 0},
...> %{x: 0, y: 1},
...> %{x: 1, y: 0},
...> %{x: 1, y: 1}
...> ])
"0 0 2 2"
"""
@spec viewbox(list(Tile.t())) :: String.t()
def viewbox([]), do: "0 0 0 0"
def viewbox(tiles) do
%{x: min_x, y: min_y} = List.first(tiles)
%{x: max_x, y: max_y} = List.last(tiles)
"#{min_x} #{min_y} #{max_x + 1 - min_x} #{max_y + 1 - min_y}"
end
end