Trying to use cljs.tools.reader.edn/read-string
on "#uuid \"a8367bc1-690e-4a73-aecf-f2b9b3ff586e\""
but it fails with "No reader function for tag uuid."
what am I doing wrong?
ExceptionInfo repl-input.cljs [line 1, col 25] No reader function for tag reader/read-string. {:type :reader-exception, :ex-kind :reader-error, :file "repl-input.cljs", :line 1, :col 25}
clojure.tools.reader.impl.errors/throw-ex (errors.clj:34)
clojure.tools.reader.impl.errors/throw-ex (errors.clj:24)
clojure.tools.reader.impl.errors/reader-error (errors.clj:40)
clojure.tools.reader.impl.errors/reader-error (errors.clj:36)
clojure.tools.reader.impl.errors/throw-unknown-reader-tag (errors.clj:206)
clojure.tools.reader.impl.errors/throw-unknown-reader-tag (errors.clj:205)
clojure.tools.reader/read-tagged (reader.clj:861)
clojure.tools.reader/read-tagged (reader.clj:848)
clojure.tools.reader/read-dispatch (reader.clj:73)
clojure.tools.reader/read-dispatch (reader.clj:68)
clojure.tools.reader/read*/fn--1314 (reader.clj:925)
clojure.tools.reader.reader-types/log-source*/fn--962 (reader_types.clj:322)
Oh, ok, it seems tagged literals are Clojure only...
@adam.kalisz tagged literals work find in CLJS too. but the stacktrace shows that you are using clojure.tools.reader
? not cljs.tools.reader
? how are you using it?
No reader function for tag reader/read-string
looks like you are using #reader/read-string
?
Can this ClojureScript snippet become more Idiomatic? I converted this JS snippet (https://www.movable-type.co.uk/scripts/latlong.html)
const R = 6371e3; // metres
const φ1 = lat1 * Math.PI/180; // φ, λ in radians
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const d = R * c; // in metres
to this CLJS
(defn gps-distance
"calculates distance between gps coordinates in km
from: {:lat :lon}
to: {:lat :lon}
"
[from to]
(let [R 6371 ;;km
pi (.-PI js/Math)
phi-1 (* (:lat from) (/ pi 180))
phi-2 (* (:lat to) (/ pi 180))
delta-phi (* (- (:lat to) (:lat from)) (/ pi 180))
delta-lambda (* (- (:lon to) (:lon from)) (/ pi 180))
a (+ (* (.sin js/Math (/ delta-phi 2))
(.sin js/Math (/ delta-phi 2)))
(* (* (.cos js/Math phi-1) (.cos js/Math phi-2))
(* (.sin js/Math (/ delta-lambda 2)) (.sin js/Math (/ delta-lambda 2)))))
c (* 2 (.atan2 js/Math (.sqrt js/Math a) (.sqrt js/Math (- 1 a))))
d (* R c)]
d))
Am not too hands-on with cljs of late, but I suppose #(.cos js/Math %)
(and the likes) can simply be replaced with js/Math.cos
- right?
Yep!
You can use map destructuring to turn (:lat from)
into from-lat
.
You can extract (/ pi 180)
because you use it four times.
You can extract (* x x)
into a separate square
function or use js/Math.pow
to avoid having to compute the same thing twice.
You could extract common math functions into extra def
s to make gps-distance
more readable.
And I think you should be able to use Greek characters in CLJS sources with no problems. Whether it's idiomatic or not - depends on the area, I'd say.
I mean it is a 1:1 translation of the js code. Maybe the code is meant to be explicit? But I think what @p-himik suggested seems the right way in general.
I really liked how you put the comment at the top explaining what the code does
I am a fan of using comments to explain why functions are there
Just in case - that's not a comment, that's a proper docstring. It's available in the var's metadata as well, i.e. as (:doc (meta #'gps-distance))
.
is it good practice to use ( ( to square ints... versus expt from the math lib...
:require [clojure.math.numeric-tower :as math
because of 1 less dependency?
Yes. It's better to use built-in functions (e.g. *
) and platform functions (e.g. js/Math.pow
) when they do exactly the same as some function from some third-party dependency.
I like your idea of extracting some of it into functions... because you can help me remember some pieces of the equations... with a well named function
e.g.. area versus circumference as a function name instead of pi r ^ 2... just as an example
Is using a top-level let
like this, a reasonable way of defining one-off fns, assuming they aren't usable elsewhere in the namespace?
(let [R 6371 ;; km
square #(* % %)
PI (/ (.-PI js/Math) 180)
cos #(.cos js/Math %)
sin #(.sin js/Math %)
atan2 #(.atan2 js/Math % %2)
sqrt #(.sqrt js/Math %)]
(defn gps-distance
"calculates distance between gps coordinates in km"
[{lat1 :lat lon1 :lon} {lat2 :lat lon2 :lon}]
(let [φ1 (* lat1 PI)
φ2 (* lat2 PI)
Δφ (* (- lat1 lat1) PI)
Δλ (* (- lon2 lon1) PI)
a (+ (square (sin (/ Δφ 2)))
(* (cos φ1) (cos φ2))
(square (sin (/ Δλ 2))))
c (* 2 (atan2 (sqrt a) (sqrt (- 1 a))))]
(* R c))))
Also, will the tiny fns like the cos
and sin
be inlined by Google Closure in advanced mode?
PS: Dunno if this is even allowed in CLJS. Haven't learned it yet.That's allowed. I can't answer the question about inlining, but I wouldn't worry about it. You have CLJS compiler running on top of GCC compiler, where the code ends up running on JS VM. You're so removed from the actual execution, that worrying about inlining such functions should be the last thing IMO.
I have an image tag that contains a url from the web:
[:img {:height 599
:width 500
:alt "Mike Wazowski"
:src "<https://static.wikia.nocookie.net/sulleycinematicuniverse/images/0/0b/Greenbillycrystalwithoneeye.jpeg/revision/latest/top-crop/width/360/height/450?cb=20190614200344>"}]
However, upon loading this component, I’m getting a 404 in the console for this url, even though the image at the source exists.Sounds like it has nothing to do with #clojurescript and everything to do with how <http://static.wikia.nocokie.net|static.wikia.nocokie.net>
processes requests. A server can choose to reply with any code, including 404, to any request.
agreed. this sounds like wikipedia saying they won't pay the hosting costs for images for your website
do you think that setting referrerpolicy would give let you use it? https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-referrerpolicy
I mean, absolutely host it yourself 😂 but if you're just playing around then maybe that'll let you get around it
What is the best way to catch a click outside a div (like a modal) in cljs+reagent?
• .addEventListener
that should be attached on componentDidMount
and detached on unmount
• a global overlay div attached to the bottom of the body
If it's just handling of clicks and nothing else, then I don't think there's any functional difference. But if you want to apply some styles to the backdrop (e.g. opacity), then it needs to be a proper DOM node.
Okay thanks!