From c356f7895bdc1cd92156676b3e255059a2a1f661 Mon Sep 17 00:00:00 2001 From: Cristine Guadelupe Date: Thu, 24 Nov 2022 23:22:01 -0300 Subject: [PATCH] Geocode source improvements (#47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Geocode source improvements * Fix - geocode source options * Fix - geocode source for postal codes * Update lib/kino_maplibre/map_cell.ex Co-authored-by: Jonatan Kłosko Co-authored-by: Jonatan Kłosko --- lib/assets/map_cell/main.js | 3 +- lib/kino_maplibre/map_cell.ex | 49 +++++++++++++++++++--------- mix.exs | 2 +- mix.lock | 2 +- test/kino_maplibre/map_cell_test.exs | 33 +++++++++++++------ 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/lib/assets/map_cell/main.js b/lib/assets/map_cell/main.js index d84d6c4..82fe9c6 100644 --- a/lib/assets/map_cell/main.js +++ b/lib/assets/map_cell/main.js @@ -148,7 +148,7 @@ export function init(ctx, payload) { label="Type" :index="index" v-model="layer.layer_type" - :options="typeOptions" + :options="layer.source_type === 'query' ? geocodeOptions : typeOptions" :disabled="noSourceVariable" :required /> @@ -262,6 +262,7 @@ export function init(ctx, payload) { dataOptions: payload.source_variables, missingDep: payload.missing_dep, typeOptions: ["circle", "fill", "line", "heatmap", "cluster"], + geocodeOptions: ["fill", "line", "circle"], styles: [ "default", "street (non-commercial)", diff --git a/lib/kino_maplibre/map_cell.ex b/lib/kino_maplibre/map_cell.ex index d3b472a..b0be7e8 100644 --- a/lib/kino_maplibre/map_cell.ex +++ b/lib/kino_maplibre/map_cell.ex @@ -10,9 +10,9 @@ defmodule KinoMapLibre.MapCell do @as_float ["layer_opacity"] @geometries [Geo.Point, Geo.LineString, Geo.Polygon, Geo.GeometryCollection] @styles %{"street (non-commercial)" => :street, "terrain (non-commercial)" => :terrain} + @geocode_options ["fill", "line", "circle"] @query_source %{columns: nil, type: "query", variable: "🌎 Geocoding"} - @query_base "https://nominatim.openstreetmap.org/search?format=geojson&limit=1&polygon_geojson=1" @impl true def init(attrs, ctx) do @@ -110,8 +110,16 @@ defmodule KinoMapLibre.MapCell do updated_source = prefill_source_options(ctx.assigns.layers, value) + layer_type = + if source_type == "query" and layer["layer_type"] not in @geocode_options, + do: "fill", + else: layer["layer_type"] + updated_fields = - Map.merge(%{"layer_source" => value, "source_type" => source_type}, updated_source) + Map.merge( + %{"layer_source" => value, "source_type" => source_type, "layer_type" => layer_type}, + updated_source + ) updated_layer = Map.merge(layer, updated_fields) updated_layers = List.replace_at(ctx.assigns.layers, idx, updated_layer) @@ -334,11 +342,11 @@ defmodule KinoMapLibre.MapCell do defp build_arg_source(id, data, :table, coordinates, opts), do: [id, Macro.var(String.to_atom(data), nil), coordinates, opts] - defp build_arg_source(id, data, :query, _, opts) do - args = [type: :geojson, data: data] - args = if opts, do: Keyword.merge(args, opts), else: args - [id, args] - end + defp build_arg_source(id, {data, nil}, :query, _, _), + do: [id, data] + + defp build_arg_source(id, {data, strict}, :query, _, _), + do: [id, data, String.to_atom(strict)] defp build_arg_source(id, data, _, _, opts) do args = [type: :geojson, data: Macro.var(String.to_atom(data), nil)] @@ -346,7 +354,6 @@ defmodule KinoMapLibre.MapCell do [id, args] end - defp build_arg_layer(nil, _, _, _, _), do: nil defp build_arg_layer(_, nil, _, _, _), do: nil defp build_arg_layer(id, source, :cluster, _, cluster_options) do @@ -414,22 +421,23 @@ defmodule KinoMapLibre.MapCell do defp build_layer_source(%{source_type: :query, layer_source_query: nil}), do: nil defp build_layer_source(%{source_type: :query} = layer) do - query = String.replace(layer.layer_source_query, ~r/\W+/, "_") + query = normalize_geocode_id(layer.layer_source_query) strict = layer.layer_source_query_strict if strict, do: "#{query}_#{strict}", else: query end defp build_layer_source(layer), do: layer.layer_source - defp source_id(%{"layer_type" => "cluster"} = layer), do: "#{layer["layer_source"]}_clustered" defp source_id(%{"source_type" => "query", "layer_source_query" => nil}), do: nil defp source_id(%{"source_type" => "query"} = layer) do - query = String.replace(layer["layer_source_query"], ~r/\W+/, "_") + query = normalize_geocode_id(layer["layer_source_query"]) strict = layer["layer_source_query_strict"] if strict, do: "#{query}_#{strict}", else: query end + defp source_id(%{"layer_type" => "cluster"} = layer), do: "#{layer["layer_source"]}_clustered" + defp source_id(layer), do: layer["layer_source"] defp source_coordinates(%{"source_type" => "table", "coordinates_format" => "columns"} = layer) do @@ -446,17 +454,14 @@ defmodule KinoMapLibre.MapCell do defp source_options(_), do: [] defp source_data(%{"source_type" => "query"} = layer) do - build_source_query(layer["layer_source_query"], layer["layer_source_query_strict"]) + {layer["layer_source_query"], layer["layer_source_query_strict"]} end defp source_data(layer), do: layer["layer_source"] - defp build_source_query(nil, _), do: nil - defp build_source_query(query, nil), do: "#{@query_base}&q=#{query}" - defp build_source_query(query, strict), do: "#{@query_base}&#{strict}=#{query}" - defp add_source_function(:geo), do: :add_geo_source defp add_source_function(:table), do: :add_table_source + defp add_source_function(:query), do: :add_geocode_source defp add_source_function(_), do: :add_source defp missing_dep() do @@ -511,4 +516,16 @@ defmodule KinoMapLibre.MapCell do valid_lat? = lat >= -90 and lat <= 90 if valid_lng? and valid_lat?, do: {lng, lat} end + + defp normalize_geocode_id(query) do + if Regex.match?(~r/^[\d-]*$/, query) do + "postalcode_#{String.replace(query, ~r/\D+/, "")}" + else + query + |> String.downcase() + |> String.normalize(:nfd) + |> String.replace(~r/[^a-zA-Z\s]/u, "") + |> String.replace(~r/\W+/, "_") + end + end end diff --git a/mix.exs b/mix.exs index 87bc494..90938e7 100644 --- a/mix.exs +++ b/mix.exs @@ -28,7 +28,7 @@ defmodule KinoMapLibre.MixProject do [ {:kino, "~> 0.6.1 or ~> 0.7.0"}, {:table, "~> 0.1.0"}, - {:maplibre, "~> 0.1.2"}, + {:maplibre, "~> 0.1.3"}, {:ex_doc, "~> 0.28", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index 388943e..702139a 100644 --- a/mix.lock +++ b/mix.lock @@ -6,7 +6,7 @@ "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, - "maplibre": {:hex, :maplibre, "0.1.2", "63fe5a071a0d2d167fded093e0958b1247890024e7a04b9429f714463a0ba4dd", [:mix], [{:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: false]}, {:req, "~> 0.3.0", [hex: :req, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "8db58a5d302125249b479397e0475d0308275b6e45dff86ceb4a01f4810c6587"}, + "maplibre": {:hex, :maplibre, "0.1.3", "510476c23ac9958d3adddc5d349f40907309718639a9b1a93eebd586a39ef2f3", [:mix], [{:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: false]}, {:req, "~> 0.3.0", [hex: :req, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "8439795a90365c4363e26a8b66676d88ef44fda8db0060279451343d2259d640"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "table": {:hex, :table, "0.1.2", "87ad1125f5b70c5dea0307aa633194083eb5182ec537efc94e96af08937e14a8", [:mix], [], "hexpm", "7e99bc7efef806315c7e65640724bf165c3061cdc5d854060f74468367065029"}, } diff --git a/test/kino_maplibre/map_cell_test.exs b/test/kino_maplibre/map_cell_test.exs index 6625ebd..7c65c41 100644 --- a/test/kino_maplibre/map_cell_test.exs +++ b/test/kino_maplibre/map_cell_test.exs @@ -297,11 +297,7 @@ defmodule KinoMapLibre.MapCellTest do assert MapCell.to_source(attrs) == """ MapLibre.new() - |> MapLibre.add_source("brazil", - type: :geojson, - data: - "https://nominatim.openstreetmap.org/search?format=geojson&limit=1&polygon_geojson=1&q=brazil" - ) + |> MapLibre.add_geocode_source("brazil", "brazil") |> MapLibre.add_layer( id: "brazil_fill_1", source: "brazil", @@ -311,6 +307,27 @@ defmodule KinoMapLibre.MapCellTest do """ end + test "source for a map with one postal code geocode source" do + layer = %{ + "layer_source_query" => "95819", + "source_type" => "query", + "layer_type" => "circle" + } + + attrs = build_attrs(layer) + + assert MapCell.to_source(attrs) == """ + MapLibre.new() + |> MapLibre.add_geocode_source("postalcode_95819", "95819") + |> MapLibre.add_layer( + id: "postalcode_95819_circle_1", + source: "postalcode_95819", + type: :circle, + paint: [circle_color: "#000000", circle_radius: 5, circle_opacity: 1] + )\ + """ + end + test "source for a map with one strict geocode source" do layer = %{ "layer_source_query" => "sao paulo", @@ -325,11 +342,7 @@ defmodule KinoMapLibre.MapCellTest do assert MapCell.to_source(attrs) == """ MapLibre.new() - |> MapLibre.add_source("sao_paulo_state", - type: :geojson, - data: - "https://nominatim.openstreetmap.org/search?format=geojson&limit=1&polygon_geojson=1&state=sao paulo" - ) + |> MapLibre.add_geocode_source("sao_paulo_state", "sao paulo", :state) |> MapLibre.add_layer( id: "sao_paulo_state_fill_1", source: "sao_paulo_state",