OK, this is fucking impressive if I say so myself.
This commit is contained in:
parent
64fd9ffb5b
commit
d001338a49
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -14,3 +14,5 @@ pom.xml
|
|||
.nrepl-port
|
||||
|
||||
resources/public/data/
|
||||
|
||||
.rebel_readline_history
|
||||
|
|
|
@ -1,2 +1,46 @@
|
|||
/* some style */
|
||||
|
||||
body {
|
||||
font-family: Helvetica, Ariel, sans-serif;
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
|
||||
div#app {
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
footer {
|
||||
clear: both;
|
||||
font-size: smaller;
|
||||
text-align: center;
|
||||
color:white;
|
||||
background-color: #3298dc;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0.25em 0;
|
||||
bottom:0;
|
||||
position:fixed;
|
||||
vertical-align: top;
|
||||
z-index:150;
|
||||
_position:absolute;
|
||||
_top:expression(eval(document.documentElement.scrollTop+
|
||||
(document.documentElement.clientHeight-this.offsetHeight)));
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding-left: 10%;
|
||||
text-align: left;
|
||||
background-color: #3298dc;
|
||||
color: white;
|
||||
}
|
||||
|
||||
samp {
|
||||
background-color: #b0b0ff;
|
||||
}
|
||||
|
|
BIN
resources/public/favicon.ico
Normal file
BIN
resources/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
|
@ -1,10 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>GeoCSV Lite</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css">
|
||||
<link rel="icon" href="https://clojurescript.org/images/cljs-logo-icon-32.png">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<!-- if you prefer loading libraries from standard hosts, un comment this and
|
||||
comment out the local source -->
|
||||
<!-- link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
|
||||
|
@ -13,11 +14,50 @@
|
|||
<link rel="stylesheet" href="vendor/node_modules/leaflet/dist/leaflet.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>GeoCSV Lite</h1>
|
||||
<div id="app">
|
||||
<h2>Figwheel template</h2>
|
||||
<p id="message">Checkout your developer console.</p>
|
||||
<div id="map" style="height: 600px; width: 80%; margin-left: 10%; border: thin solid gray;"></div>
|
||||
<p id="message"></p>
|
||||
<p id="error"></p>
|
||||
<div id="map" style="height: 600px; width: 80%; border: thin solid gray;"></div>
|
||||
</div>
|
||||
<div id="doc">
|
||||
<p>
|
||||
Use this page as a crib for how to use <b>GeoCSV Lite</b> in your projects. In order
|
||||
for it to work, you need:
|
||||
<ol>
|
||||
<li>Javascript dependencies:
|
||||
<ol>
|
||||
<li><a href="">Leaflet</a> (provides mapping);</li>
|
||||
<li><a href="">PapaParse</a> (provides CSV parsing);</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>
|
||||
A line which includes the geocsv_lite library, which should be
|
||||
<em>after</em> those including the dependencies: <br/>
|
||||
<samp><script src="js/compiled/geocsv_lite.js"
|
||||
type="text/javascript"></script></samp>
|
||||
</li>
|
||||
<li>One (or more) <code>div</code> elements to contain your maps. It
|
||||
is a requirement of Leaflet that these must have a fixed pixel width.
|
||||
Each must have a distinct <code>id</code>;</li>
|
||||
<li>
|
||||
For each <code>div</code> which you wish to contain a map view,
|
||||
an invocation of the function
|
||||
<code>geocsv_lite.core.initialise_map_element(id, data-source)</code>: <br/>
|
||||
<samp><script>geocsv_lite.core.initialise_map_element("map", "/data/data.csv");</script></samp>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<footer>
|
||||
<div id="credits">
|
||||
<div>
|
||||
<img height="16" width="16" alt="Clojure" src="img/credits/clojure-icon.gif"/> Powered by <a href="http://clojure.org">Clojure</a> ||
|
||||
<img height="16" width="16" alt="GitHub" src="img/credits/github-logo-transparent.png"/>Find me/fork me on <a href="https://github.com/simon-brooke/geocsv-lite">Github</a> ||
|
||||
<img height="16" width="16" alt="Free Software Foundation" src="img/credits/gnu.small.png"/>Licensed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License version 2.0</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- if you prefer loading libraries from standard hosts, un comment this and
|
||||
comment out the local source -->
|
||||
<!-- script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
|
||||
|
@ -27,5 +67,8 @@
|
|||
<script src="vendor/node_modules/leaflet/dist/leaflet.js"></script>
|
||||
<script src="vendor/node_modules/papaparse/papaparse.min.js"></script>
|
||||
<script src="js/compiled/geocsv_lite.js" type="text/javascript"></script>
|
||||
<script>
|
||||
geocsv_lite.core.initialise_map_element("map", "/data/data.csv");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
[geocsv-lite.gis :as gis]
|
||||
[geocsv-lite.map :as m]))
|
||||
|
||||
(enable-console-print!)
|
||||
|
||||
(println "This text is printed from src/geocsv-lite/core.cljs. Go ahead and edit it and see reloading in action.")
|
||||
|
||||
|
||||
|
||||
|
||||
;; define your app data so that it doesn't get over-written on reload
|
||||
(defn ^:export initialise-map-element
|
||||
"Create a map view in the element with this `id` and decorate it with
|
||||
pins showing locations from this `data-source`."
|
||||
[id data-source]
|
||||
(js/console.log (str "geocsv-lite.core.initialise-map-element called with args id: " id "; data-source: " data-source "."))
|
||||
(let [sid (str id)
|
||||
kid (keyword sid)
|
||||
v (m/add-view sid 55 -4 10)]
|
||||
(.whenReady v (fn [] (get-data kid data-source)))))
|
||||
|
||||
(defonce app-state (atom {:text "Hello world!"}))
|
||||
|
||||
|
@ -21,11 +23,4 @@
|
|||
;; optionally touch your app-state to force rerendering depending on
|
||||
;; your application
|
||||
;; (swap! app-state update-in [:__figwheel_counter] inc)
|
||||
(m/add-view "map" 55 -4 10)
|
||||
(let [query (get-query-part-as-map)
|
||||
uri (get-csv-url query)
|
||||
records (get-data :map)]
|
||||
(dom/set-text (.getElementById js/document "message")
|
||||
(str "Query was: " query "; uri was: " uri))))
|
||||
|
||||
|
||||
)
|
||||
|
|
|
@ -8,20 +8,12 @@
|
|||
[geocsv-lite.map :refer [get-view]]
|
||||
))
|
||||
|
||||
;; function getQueryVariable(variable)
|
||||
;; {
|
||||
;; var query = window.location.search.substring(1);
|
||||
;; var vars = query.split("&");
|
||||
;; for (var i=0;i<vars.length;i++) {
|
||||
;; var pair = vars[i].split("=");
|
||||
;; if(pair[0] == variable){return pair[1];}
|
||||
;; }
|
||||
;; return(false);
|
||||
;; }
|
||||
|
||||
|
||||
|
||||
(defn get-query-part-as-map
|
||||
"Returns the query part of the current document URL as a keyword-string map."
|
||||
;; not actually used in the current incarnation
|
||||
[]
|
||||
(let [query-nvs (map #(cs/split % "=") (cs/split (subs js/window.location.search 1) "&"))]
|
||||
(when (every? #(= (count %) 2) query-nvs)
|
||||
|
@ -35,6 +27,7 @@
|
|||
* `:uri` whose value is the URI of a JSON or CSV file.
|
||||
|
||||
If either of these keys is found, returns an appropriate URL, else nil."
|
||||
;; not actually used in the current incarnation
|
||||
[query]
|
||||
(when (map? query)
|
||||
(cond
|
||||
|
@ -46,13 +39,26 @@
|
|||
|
||||
|
||||
(defn default-handler
|
||||
"When data is received from a URL, it is received asynchronously. This
|
||||
is the default callback called with the `response` of the HTTP request,
|
||||
and the keyword `k` identifying the map view, to populate the map with
|
||||
data."
|
||||
[response k]
|
||||
(if
|
||||
(= (:status response) 200)
|
||||
(let [content (:body response)
|
||||
data (js->clj (.-data (.parse js/Papa content)))
|
||||
data (map
|
||||
#(merge %
|
||||
{:longitude (js/Number (:longitude %))
|
||||
:latitide (js/Number (:latitude %))})
|
||||
(js->clj (.-data (.parse js/Papa content (clj->js {:dynamicTyping true})))))
|
||||
cols (map
|
||||
#(let [n (cs/lower-case (cs/replace (cs/trim %) #"[^\w\d]+" "-"))]
|
||||
#(let [n (when-not
|
||||
(empty? %)
|
||||
(when (string? %)
|
||||
(cs/lower-case
|
||||
(cs/replace
|
||||
% #"[^\w\d]+" "-"))))]
|
||||
(keyword
|
||||
(if (empty? n)
|
||||
(gensym)
|
||||
|
@ -62,19 +68,21 @@
|
|||
(fn [r] (zipmap cols (map str r)))
|
||||
(rest data))
|
||||
]
|
||||
;; (println records)
|
||||
(gis/refresh-map-pins (get-view k) records))
|
||||
(println (str "Bad response from server: " (:status response)))))
|
||||
(js/console.error (str "Bad response from server: " (:status response)))))
|
||||
|
||||
|
||||
(defn get-data
|
||||
[k]
|
||||
"Get data for the view identified by this keyword `k` from this `data-source`.
|
||||
In this initial release the data source must be a URL, but in future releases
|
||||
I intend that it may also be a list of maps representing records, or a CSV or
|
||||
JSON formatted string."
|
||||
[k data-source]
|
||||
(let
|
||||
[uri (get-csv-url (get-query-part-as-map))]
|
||||
[uri data-source]
|
||||
(go (let [response (<! (http/get uri {:with-credentials? "false"
|
||||
:access-control-allow-credentials "true"
|
||||
:origin js/window.location.hostname}))]
|
||||
(println (cs/join " " ["tx:" uri "rx:" (:status response)]))
|
||||
(default-handler response k)))))
|
||||
|
||||
(defn get-data-with-uri-and-handler
|
||||
|
@ -83,7 +91,7 @@
|
|||
(apply handler-fn (list response k)))))
|
||||
|
||||
|
||||
(go (let [uri "http://localhost:3449/data/data.csv"
|
||||
response (<! (http/get uri))]
|
||||
(when (= (:status response) 200)
|
||||
(default-handler response :map))))
|
||||
;; (go (let [uri "http://localhost:3449/data/data.csv"
|
||||
;; response (<! (http/get uri))]
|
||||
;; (when (= (:status response) 200)
|
||||
;; (default-handler response :map))))
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
"Add an appropriate map-pin for this `record` in this map `view`, if it
|
||||
has a valid `:latitude` and `:longitude`."
|
||||
[record index view]
|
||||
(let [lat (:latitude record)
|
||||
lng (:longitude record)]
|
||||
(let [lat (js/Number (:latitude record))
|
||||
lng (js/Number (:longitude record))]
|
||||
(if
|
||||
(and
|
||||
(number? lat)
|
||||
|
@ -170,10 +170,10 @@
|
|||
centre of the locations of these records as indicated by the values of their
|
||||
`:latitude` and `:longitude` keys."
|
||||
[records]
|
||||
(let [lats (filter number? (map :latitude records))
|
||||
(let [lats (map js/Number (map :latitude records))
|
||||
min-lat (apply min lats)
|
||||
max-lat (apply max lats)
|
||||
lngs (filter number? (map :longitude records))
|
||||
lngs (filter js/Number (map :longitude records))
|
||||
min-lng (apply min lngs)
|
||||
max-lng (apply max lngs)]
|
||||
(if-not
|
||||
|
@ -187,9 +187,10 @@
|
|||
"Refresh the map pins on the current map. Side-effecty; liable to be
|
||||
problematic."
|
||||
[view records]
|
||||
(js/console.log "refresh-map-pins called")
|
||||
(let [view (map-remove-pins view)
|
||||
centre (compute-centre records)]
|
||||
(js/console.log (str "refresh-map-pins called; " (count records) " records, centre at " centre))
|
||||
(js/console.log (str "Type of longitude " (:longitude (first records)) " is: " (type (:longitude (first records)))))
|
||||
(if
|
||||
view
|
||||
(let [added (remove nil? (map #(add-map-pin %1 %2 view) records (range)))]
|
||||
|
|
|
@ -72,16 +72,20 @@
|
|||
|
||||
(defn add-view
|
||||
[id lat lng zoom]
|
||||
(let [k (keyword id)]
|
||||
(when-not
|
||||
(let [k (keyword id)
|
||||
v (or
|
||||
(@views k)
|
||||
(swap! views assoc k (map-did-mount id lat lng zoom)))
|
||||
(views k)))
|
||||
(map-did-mount id lat lng zoom))]
|
||||
(js/console.log (str "Added Leaflet view to element with id `" id "`"))
|
||||
(swap! views assoc k v)
|
||||
v))
|
||||
|
||||
|
||||
(defn get-view
|
||||
[k]
|
||||
(@views k))
|
||||
(when-not (keyword? k) (js/console.log "Key `" k "` passed to get-view is not a keyword"))
|
||||
(when-not (k @views) (js/console.log "Key `" k "` does not identify a known view"))
|
||||
(k @views))
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue