From e2c8b71ee878d289f1e46bd615ad28335be98eb0 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 24 Jan 2020 10:22:14 +0000 Subject: [PATCH] Nothing works yet. --- .gitignore | 2 + project.clj | 15 ++-- src/cljs/datamapper/core.cljs | 52 +++++++++---- src/cljs/datamapper/views/map.cljs | 118 +++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 src/cljs/datamapper/views/map.cljs diff --git a/.gitignore b/.gitignore index a4cb69a..27ce5a0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ pom.xml.asc .lein-failures .nrepl-port .cpcache/ + +log/ diff --git a/project.clj b/project.clj index 5f23435..97af397 100644 --- a/project.clj +++ b/project.clj @@ -6,6 +6,7 @@ :dependencies [[ch.qos.logback/logback-classic "1.2.3"] [cheshire "5.9.0"] [cljs-ajax "0.8.0"] + [cljsjs/leaflet "1.5.1-0"] ;; leaflet-reagent-reframe uses this and it works with Firefox! [clojure.java-time "0.3.2"] [com.cognitect/transit-clj "0.8.319"] [cprop "0.1.15"] @@ -36,7 +37,7 @@ [selmer "1.12.18"]] :min-lein-version "2.0.0" - + :source-paths ["src/clj" "src/cljs" "src/cljc"] :test-paths ["test/clj"] :resource-paths ["resources" "target/cljsbuild"] @@ -52,7 +53,7 @@ :nrepl-port 7002 :css-dirs ["resources/public/css"] :nrepl-middleware [cider.piggieback/wrap-cljs-repl]} - + :profiles {:uberjar {:omit-source true @@ -70,7 +71,7 @@ :closure-warnings {:externs-validation :off :non-standard-jsdoc :off} :externs ["react/externs/react.js"]}}}} - + :aot :all :uberjar-name "datamapper.jar" :source-paths ["env/prod/clj"] @@ -107,8 +108,8 @@ :source-map true :main "datamapper.app" :pretty-print true}}}} - - + + :doo {:build "test"} :source-paths ["env/dev/clj"] :resource-paths ["env/dev/resources"] @@ -117,7 +118,7 @@ (pjstadig.humane-test-output/activate!)]} :project/test {:jvm-opts ["-Dconf=test-config.edn"] :resource-paths ["env/test/resources"] - :cljsbuild + :cljsbuild {:builds {:test {:source-paths ["src/cljc" "src/cljs" "test/cljs"] @@ -126,7 +127,7 @@ :main "datamapper.doo-runner" :optimizations :whitespace :pretty-print true}}}} - + } :profiles/dev {} :profiles/test {}}) diff --git a/src/cljs/datamapper/core.cljs b/src/cljs/datamapper/core.cljs index 5191df8..4e3e4a8 100644 --- a/src/cljs/datamapper/core.cljs +++ b/src/cljs/datamapper/core.cljs @@ -1,5 +1,6 @@ (ns datamapper.core (:require + [clojure.string :refer [capitalize]] [day8.re-frame.http-fx] [reagent.core :as r] [re-frame.core :as rf] @@ -8,6 +9,7 @@ [markdown.core :refer [md->html]] [datamapper.ajax :as ajax] [datamapper.events] + [datamapper.views.map :as maps] [reitit.core :as reitit] [reitit.frontend.easy :as rfe] [clojure.string :as string]) @@ -19,6 +21,39 @@ :class (when (= page @(rf/subscribe [:page])) :is-active)} title]) +(defn about-page [] + [:section.section>div.container>div.content + [:img {:src "/img/warning_clojure.png"}]]) + +(defn map-page + "Return the content for the main map page. Map showing current location." + [] + (maps/panel)) + +(defn home-page [] + [:section.section>div.container>div.content + (when-let [docs @(rf/subscribe [:docs])] + [:div {:dangerouslySetInnerHTML {:__html (md->html docs)}}])]) + +(def pages + {:home #'home-page + :map #'map-page + :about #'about-page}) + +(defn auto-nav + "Automatically create a navbar for all the pages we know about." + [] + (apply vector + (cons + :div.navbar-start + (map + #(apply vector + (list + (str "#/" (if (= % :home) "" (name %))) + (capitalize (name %)) + %)) + (keys pages))))) + (defn navbar [] (r/with-let [expanded? (r/atom false)] [:nav.navbar.is-info>div.container @@ -31,22 +66,7 @@ [:span][:span][:span]]] [:div#nav-menu.navbar-menu {:class (when @expanded? :is-active)} - [:div.navbar-start - [nav-link "#/" "Home" :home] - [nav-link "#/about" "About" :about]]]])) - -(defn about-page [] - [:section.section>div.container>div.content - [:img {:src "/img/warning_clojure.png"}]]) - -(defn home-page [] - [:section.section>div.container>div.content - (when-let [docs @(rf/subscribe [:docs])] - [:div {:dangerouslySetInnerHTML {:__html (md->html docs)}}])]) - -(def pages - {:home #'home-page - :about #'about-page}) + (auto-nav)]])) (defn page [] (if-let [page @(rf/subscribe [:page])] diff --git a/src/cljs/datamapper/views/map.cljs b/src/cljs/datamapper/views/map.cljs new file mode 100644 index 0000000..5853df8 --- /dev/null +++ b/src/cljs/datamapper/views/map.cljs @@ -0,0 +1,118 @@ +(ns ^{:doc "datamapper app map view panel." + :author "Simon Brooke"} + datamapper.views.map + (:require [cljsjs.leaflet] + [re-frame.core :refer [reg-sub subscribe dispatch dispatch-sync]] + [reagent.core :as reagent] + [recalcitrant.core :refer [error-boundary]] + [youyesyet.canvasser-app.gis :refer [refresh-map-pins get-current-location]])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; +;;;; youyesyet.canvasser-app.views.map: map view for youyesyet. +;;;; +;;;; This program is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU General Public License +;;;; as published by the Free Software Foundation; either version 2 +;;;; of the License, or (at your option) any later version. +;;;; +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with this program; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +;;;; USA. +;;;; +;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign +;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have +;;; one source file/namespace per view. Each namespace contains a function 'panel' +;;; whose output is an enlive-style specification of the view to be redered. +;;; I propose to follow this pattern. This file will (eventually) provide the map view. + +;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#map-view + +;;; Cribbed heavily from +;;; https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/leaflet +;;; but using OSM data because we can't afford commercial, so also cribbed from +;;; https://switch2osm.org/using-tiles/getting-started-with-leaflet/ +;;; Note that this is raw reagent stylee; it should be refactoed into re-frame stylee +;;; when I understand it better. + +;;; There should be one flag on the map for each address record currently in frame. +;;; Clicking the flag sets that address as the current address in the app state, +;;; and redirects to the electors view. How we handle blocks of flats needs further +;;; thought. + +;; which provider to use +(def ^:dynamic *map-provider* :osm) + +(def osm-url "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png") +(def osm-attrib "Map data © OpenStreetMap contributors") + +;; My gods mapbox is user-hostile! +(defn map-did-mount-mapbox + "Did-mount function loading map tile data from MapBox (proprietary)." + [] + (get-current-location) + (let [view (.setView + (.map js/L "map" (clj->js {:zoomControl "false"})))] + ;; NEED TO REPLACE FIXME with your mapID! + (.addTo (.tileLayer js/L "http://{s}.tiles.mapbox.com/v3/FIXME/{z}/{x}/{y}.png" + (clj->js {:attribution "Map data © [...]" + :maxZoom 18}))) + view)) + + +(defn map-did-mount-osm + "Did-mount function loading map tile data from Open Street Map." + [] + (get-current-location) ;; - [Violation] Only request geolocation information in response to a user gesture. + (let [view (.setView + (.map js/L + "map" + (clj->js {:zoomControl false})) + #js [@(subscribe [:latitude]) @(subscribe [:longitude])] + @(subscribe [:zoom]))] + (.addTo (.tileLayer js/L osm-url + (clj->js {:attribution osm-attrib + :maxZoom 18})) + view) + (dispatch-sync [:set-view view]) + (.on view "moveend" + (fn [_] (let [c (.getCenter view)] + (js/console.log (str "Moving centre to " c)) + (dispatch-sync [:set-latitude (.-lat c)]) + (dispatch-sync [:set-longitude (.-lng c)]) + (dispatch [:fetch-locality])))) + (refresh-map-pins) + view)) + + +(defn map-did-mount + "Select the actual map provider to use." + [] + (dispatch-sync [:set-view (case *map-provider* + :mapbox (map-did-mount-mapbox) + :osm (map-did-mount-osm) + ;; potentially others + )])) + + +(defn map-render + "Render the actual div containing the map." + [] + [:div#map {:style {:height "500px"}}]) + + +(defn panel + "A reagent class for the map object." + [] + ;; (get-current-location) + (reagent/create-class {:reagent-render map-render + :component-did-mount map-did-mount}))