clementine 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +4 -2
- data/LICENSE.txt +22 -0
- data/README.md +11 -6
- data/Rakefile +22 -0
- data/clementine.gemspec +2 -1
- data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
- data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
- data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
- data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
- data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
- data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
- data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
- data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
- data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
- data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
- data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
- data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
- data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
- data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
- data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
- data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
- data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
- data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
- data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
- data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
- data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
- data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
- data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
- data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
- data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
- data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
- data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
- data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
- data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
- data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
- data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
- data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
- data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
- data/lib/clementine.rb +3 -24
- data/lib/clementine/clojurescript_engine.rb +9 -48
- data/lib/clementine/clojurescript_engine/base.rb +15 -0
- data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
- data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
- data/lib/clementine/version.rb +1 -1
- data/test/clojurescript_engine_test.rb +36 -14
- metadata +177 -83
- data/vendor/assets/lib/clojure.jar +0 -0
- data/vendor/assets/lib/compiler.jar +0 -0
- data/vendor/assets/lib/goog.jar +0 -0
- data/vendor/assets/lib/js.jar +0 -0
- data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
- data/vendor/assets/src/clj/cljs/core.clj +0 -702
- data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
- data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
- data/vendor/assets/src/cljs/cljs/reader.cljs +0 -360
@@ -0,0 +1,95 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns twitterbuzz.dom-helpers
|
10
|
+
(:require [clojure.string :as string]
|
11
|
+
[goog.dom :as dom]))
|
12
|
+
|
13
|
+
(defn get-element
|
14
|
+
"Return the element with the passed id."
|
15
|
+
[id]
|
16
|
+
(dom/getElement (name id)))
|
17
|
+
|
18
|
+
(defn append
|
19
|
+
"Append all children to parent."
|
20
|
+
[parent & children]
|
21
|
+
(do (doseq [child children]
|
22
|
+
(dom/appendChild parent child))
|
23
|
+
parent))
|
24
|
+
|
25
|
+
(defn set-text
|
26
|
+
"Set the text content for the passed element returning the
|
27
|
+
element. If a keyword is passed in the place of e, the element with
|
28
|
+
that id will be used and returned."
|
29
|
+
[e s]
|
30
|
+
(let [e (if (keyword? e) (get-element e) e)]
|
31
|
+
(doto e (dom/setTextContent s))))
|
32
|
+
|
33
|
+
(defn normalize-args [tag args]
|
34
|
+
(let [parts (string/split (name tag) #"(\.|#)")
|
35
|
+
[tag attrs] [(first parts)
|
36
|
+
(apply hash-map (map #(cond (= % ".") :class
|
37
|
+
(= % "#") :id
|
38
|
+
:else %)
|
39
|
+
(rest parts)))]]
|
40
|
+
(if (map? (first args))
|
41
|
+
[tag (merge attrs (first args)) (rest args)]
|
42
|
+
[tag attrs args])))
|
43
|
+
|
44
|
+
(defn element
|
45
|
+
"Create a dom element using a keyword for the element name and a map
|
46
|
+
for the attributes. Append all children to parent. If the first
|
47
|
+
child is a string then the string will be set as the text content of
|
48
|
+
the parent and all remaining children will be appended."
|
49
|
+
[tag & args]
|
50
|
+
(let [[tag attrs children] (normalize-args tag args)
|
51
|
+
parent (dom/createDom (name tag)
|
52
|
+
(reduce (fn [o [k v]]
|
53
|
+
(aset o k v))
|
54
|
+
(js-obj)
|
55
|
+
(map #(vector (name %1) %2)
|
56
|
+
(keys attrs)
|
57
|
+
(vals attrs))))
|
58
|
+
[parent children] (if (string? (first children))
|
59
|
+
[(set-text (element tag attrs) (first children))
|
60
|
+
(rest children)]
|
61
|
+
[parent children])]
|
62
|
+
(apply append parent children)))
|
63
|
+
|
64
|
+
(defn remove-children
|
65
|
+
"Remove all children from the element with the passed id."
|
66
|
+
[id]
|
67
|
+
(let [parent (dom/getElement (name id))]
|
68
|
+
(do (dom/removeChildren parent))))
|
69
|
+
|
70
|
+
(defn html
|
71
|
+
"Create a dom element from an html string."
|
72
|
+
[s]
|
73
|
+
(dom/htmlToDocumentFragment s))
|
74
|
+
|
75
|
+
(defn- element-arg? [x]
|
76
|
+
(or (keyword? x)
|
77
|
+
(map? x)
|
78
|
+
(string? x)))
|
79
|
+
|
80
|
+
(defn build
|
81
|
+
"Build up a dom element from nested vectors."
|
82
|
+
[x]
|
83
|
+
(if (vector? x)
|
84
|
+
(let [[parent children] (if (keyword? (first x))
|
85
|
+
[(apply element (take-while element-arg? x))
|
86
|
+
(drop-while element-arg? x)]
|
87
|
+
[(first x) (rest x)])
|
88
|
+
children (map build children)]
|
89
|
+
(apply append parent children))
|
90
|
+
x))
|
91
|
+
|
92
|
+
(defn insert-at
|
93
|
+
"Insert a child element at a specific location."
|
94
|
+
[parent child index]
|
95
|
+
(dom/insertChildAt parent child index))
|
@@ -0,0 +1,100 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns twitterbuzz.layout
|
10
|
+
(:require [twitterbuzz.anneal :as ann]
|
11
|
+
[twitterbuzz.radial :as rad]
|
12
|
+
[goog.math :as math]))
|
13
|
+
|
14
|
+
(defn random-loc []
|
15
|
+
{:x (ann/random) :y (ann/random)})
|
16
|
+
|
17
|
+
(defn sqr [x]
|
18
|
+
(* x x))
|
19
|
+
|
20
|
+
(defn sqrt [x]
|
21
|
+
(js/Math.sqrt x))
|
22
|
+
|
23
|
+
(defn dist [{x1 :x y1 :y} {x2 :x y2 :y}]
|
24
|
+
(sqrt (+ (sqr (- x2 x1)) (sqr (- y2 y1)))))
|
25
|
+
|
26
|
+
(defn init-state [mentions-data]
|
27
|
+
(let [connected (reduce (fn [ret [k {:keys [mentions]}]]
|
28
|
+
(if (pos? (count mentions))
|
29
|
+
(into (conj ret k) (keys mentions))
|
30
|
+
ret))
|
31
|
+
#{} mentions-data)
|
32
|
+
mentions-data (select-keys mentions-data connected)]
|
33
|
+
{:locs (zipmap connected (repeatedly #(random-loc)))
|
34
|
+
:mentions mentions-data}))
|
35
|
+
|
36
|
+
(defn roots [mentions-data]
|
37
|
+
(let [parents (reduce (fn [ret [k {:keys [mentions]}]]
|
38
|
+
(if (pos? (count mentions))
|
39
|
+
(conj ret k)
|
40
|
+
ret))
|
41
|
+
#{} mentions-data)]
|
42
|
+
(reduce disj parents (mapcat #(keys (:mentions %)) (vals mentions-data)))))
|
43
|
+
|
44
|
+
(defn radial
|
45
|
+
[mentions-data]
|
46
|
+
(let [mentions #(rad/get-mentions mentions-data %)
|
47
|
+
weights (rad/weights
|
48
|
+
(into (set (roots mentions-data)) (mapcat mentions (keys mentions-data)))
|
49
|
+
mentions)]
|
50
|
+
{:mentions mentions-data
|
51
|
+
:locs (-> (rad/layout (roots mentions-data) weights mentions)
|
52
|
+
(rad/polar->cartesian 3))}))
|
53
|
+
|
54
|
+
(defn score [{:keys [locs mentions]}]
|
55
|
+
(let [metric (fn [d w] (sqr (- 1 (* d w))))
|
56
|
+
score-user (fn [[k {:keys [mentions]}]]
|
57
|
+
(if (zero? (count mentions))
|
58
|
+
0
|
59
|
+
(let [loc (locs k)]
|
60
|
+
(reduce (fn [score [ok w]]
|
61
|
+
(+ score (metric (dist loc (locs ok)) w)))
|
62
|
+
0
|
63
|
+
mentions))))]
|
64
|
+
(reduce + (map score-user mentions))))
|
65
|
+
|
66
|
+
(defn permute-swap [{:keys [locs mentions]} t]
|
67
|
+
;;first cut - swap
|
68
|
+
(let [xys (vec (vals locs))
|
69
|
+
swap1 (math/randomInt (count xys))
|
70
|
+
swap2 (math/randomInt (count xys))
|
71
|
+
temp (xys swap1)
|
72
|
+
xys (assoc xys swap1 (xys swap2))
|
73
|
+
xys (assoc xys swap2 temp)]
|
74
|
+
{:locs (zipmap (keys locs) xys)
|
75
|
+
:mentions mentions}))
|
76
|
+
|
77
|
+
(defn permute-move [{:keys [locs mentions]} t]
|
78
|
+
(let [adj #(min 1.0 (max 0 (+ % (- (* (ann/random) 0.1) 0.05))))
|
79
|
+
move (fn [{:keys [x y] :as loc}]
|
80
|
+
(if true ;;(> (ann/random) 0.8)
|
81
|
+
{:x (adj x)
|
82
|
+
:y (adj y)}
|
83
|
+
loc))
|
84
|
+
xys (vec (vals locs))]
|
85
|
+
{:locs (zipmap (keys locs) (map move (vals locs)))
|
86
|
+
:mentions mentions}))
|
87
|
+
|
88
|
+
(comment
|
89
|
+
(def test-data {})
|
90
|
+
|
91
|
+
(def init (init-state test-data))
|
92
|
+
|
93
|
+
(map (fn [x] {:best-score (:best-score x) :t (:t x)})
|
94
|
+
(take 10 (take-nth 100
|
95
|
+
(ann/anneal score
|
96
|
+
(ann/linear-cooling 1000)
|
97
|
+
permute-move
|
98
|
+
ann/standard-prob
|
99
|
+
init))))
|
100
|
+
)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns twitterbuzz.leaderboard
|
10
|
+
(:require [twitterbuzz.core :as buzz]
|
11
|
+
[twitterbuzz.dom-helpers :as dom]))
|
12
|
+
|
13
|
+
(defn leaderboard-element
|
14
|
+
"Create a leaderboard element from a user map."
|
15
|
+
[user]
|
16
|
+
(dom/build [:div.tweet
|
17
|
+
[:img.profile-pic {:src (:image-url user)}]
|
18
|
+
[:div.tweet-details
|
19
|
+
[:div.user-name (:username user)]
|
20
|
+
[:div.tweet-text (dom/html (buzz/markup (:last-tweet user)))]
|
21
|
+
[:div (str (buzz/num-mentions user))]]]))
|
22
|
+
|
23
|
+
(defn leaders
|
24
|
+
"Given a map of users, return a sequence of users in order of the
|
25
|
+
greatest to least number of mentions."
|
26
|
+
[nodes]
|
27
|
+
(reverse (sort-by #(buzz/num-mentions (second %)) nodes)))
|
28
|
+
|
29
|
+
(defn update-leaderboard
|
30
|
+
"Put the top 5 mentioned users in the leaderboard."
|
31
|
+
[graph]
|
32
|
+
(do (dom/remove-children :leaderboard-content)
|
33
|
+
(doseq [next-node (take 5 (leaders (seq graph)))]
|
34
|
+
(dom/append (dom/get-element :leaderboard-content)
|
35
|
+
(leaderboard-element (second next-node))))))
|
36
|
+
|
37
|
+
;; Register event listeners.
|
38
|
+
|
39
|
+
(buzz/register :track-clicked #(dom/remove-children :leaderboard-content))
|
40
|
+
(buzz/register :graph-update update-leaderboard)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns twitterbuzz.radial
|
10
|
+
(:require [clojure.set :as set]
|
11
|
+
[goog.math :as math]))
|
12
|
+
|
13
|
+
(defn get-mentions
|
14
|
+
"Returns the set of mentions for k in mentions-data"
|
15
|
+
[mentions-data k]
|
16
|
+
(-> (get-in mentions-data [k :mentions])
|
17
|
+
keys
|
18
|
+
set))
|
19
|
+
|
20
|
+
(defn get-descendants
|
21
|
+
"Given child-fn (a map of parent to child), and k, return the
|
22
|
+
set of all k's descendants. Set includes k."
|
23
|
+
[child-fn k]
|
24
|
+
(loop [kids #{k}
|
25
|
+
check #{k}]
|
26
|
+
(let [[c] (seq check)]
|
27
|
+
(if c
|
28
|
+
(recur (into kids (child-fn c))
|
29
|
+
(into (disj check c) (remove kids (child-fn c))))
|
30
|
+
kids))))
|
31
|
+
|
32
|
+
(defn weight
|
33
|
+
"Weight of noce, given child-fn (mapping of node to set
|
34
|
+
of kids)."
|
35
|
+
[node child-fn]
|
36
|
+
(if-let [kids (seq (child-fn node))]
|
37
|
+
(reduce + (map #(weight % child-fn) kids))
|
38
|
+
1))
|
39
|
+
|
40
|
+
(defn weights
|
41
|
+
"Return a map of node to its weight,
|
42
|
+
using child-fn to get the set of children for a node."
|
43
|
+
[nodes child-fn]
|
44
|
+
(reduce
|
45
|
+
(fn [m n] (assoc m n (weight n child-fn)))
|
46
|
+
{}
|
47
|
+
nodes))
|
48
|
+
|
49
|
+
(defn layout
|
50
|
+
"Returns a map of node => :radius, :slice, :angle.
|
51
|
+
|
52
|
+
weight-fn: one arg fn of node returning weight
|
53
|
+
child-fn: one arg fn of node returning set of nodes"
|
54
|
+
([nodes weight-fn child-fn]
|
55
|
+
(layout nodes weight-fn child-fn 1 0 360 #{}))
|
56
|
+
([nodes weight-fn child-fn radius a1 a2 seen]
|
57
|
+
(let [slice (- a2 a1)
|
58
|
+
total-weight (reduce + (map #(or (weight-fn %)
|
59
|
+
(throw (str "No weight for " %))) nodes))
|
60
|
+
seen (into seen nodes)]
|
61
|
+
(loop [m {}
|
62
|
+
c1 a1
|
63
|
+
[node & more] (seq nodes)]
|
64
|
+
(if node
|
65
|
+
(let [s (* slice (/ (weight-fn node) total-weight))
|
66
|
+
c2 (+ c1 s)]
|
67
|
+
(recur
|
68
|
+
(merge
|
69
|
+
m
|
70
|
+
{node {:radius radius :slice s :angle (/ (+ c1 c2) 2)}}
|
71
|
+
(when-let [children (seq (remove seen (child-fn node)))]
|
72
|
+
(layout children weight-fn child-fn (inc radius) c1 c2 seen)))
|
73
|
+
c2
|
74
|
+
more))
|
75
|
+
m)))))
|
76
|
+
|
77
|
+
(defn polar->cartesian
|
78
|
+
"Convert polar coordinates (from layout) into
|
79
|
+
cartesian coordinates on the unit square, assuming the
|
80
|
+
square will display max-rings rings."
|
81
|
+
[polar-map max-rings]
|
82
|
+
(reduce
|
83
|
+
(fn [m [k {:keys [radius angle]}]]
|
84
|
+
(let [r (/ radius (+ 0.5 max-rings) 2)]
|
85
|
+
(assoc m k {:x (+ 0.5 (math/angleDx angle r))
|
86
|
+
:y (+ 0.5 (math/angleDy angle r))})))
|
87
|
+
{}
|
88
|
+
polar-map))
|
89
|
+
|
90
|
+
|
91
|
+
|
@@ -0,0 +1,121 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns twitterbuzz.showgraph
|
10
|
+
(:require [twitterbuzz.core :as buzz]
|
11
|
+
[twitterbuzz.layout :as layout]
|
12
|
+
[twitterbuzz.dom-helpers :as dom]
|
13
|
+
[twitterbuzz.timeline :as timeline]
|
14
|
+
[goog.events :as events]
|
15
|
+
[goog.style :as style]
|
16
|
+
[goog.math.Coordinate :as Coordinate]
|
17
|
+
[goog.ui.HoverCard :as HoverCard]
|
18
|
+
[goog.graphics.Font :as Font]
|
19
|
+
[goog.graphics.Stroke :as Stroke]
|
20
|
+
[goog.graphics.SolidFill :as SolidFill]
|
21
|
+
[goog.graphics :as graphics]))
|
22
|
+
|
23
|
+
; Drawing configuration
|
24
|
+
(def avatar-size 32) ; used for both x and y dimensions of avatars
|
25
|
+
; fail whale
|
26
|
+
;(def default-avatar "http://farm3.static.flickr.com/2562/4140195522_e207b97280_s.jpg")
|
27
|
+
; google+ silhouette
|
28
|
+
(def default-avatar "http://ssl.gstatic.com/s2/profiles/images/silhouette48.png")
|
29
|
+
(defn debug [_])
|
30
|
+
;(defn debug [a] (str "t: " (:t a) " score: " (:best-score a)))
|
31
|
+
|
32
|
+
; BAD HACK: don't change globals like this -- find a better way:
|
33
|
+
;(set! anim/TIMEOUT 500)
|
34
|
+
|
35
|
+
(def edge-stroke (graphics/Stroke. 1 "#009"))
|
36
|
+
|
37
|
+
(def g
|
38
|
+
(doto (graphics/createGraphics "100%" "100%")
|
39
|
+
(.render (dom/get-element :network))))
|
40
|
+
|
41
|
+
(def font (graphics/Font. 12 "Arial"))
|
42
|
+
(def fill (graphics/SolidFill. "#f00"))
|
43
|
+
|
44
|
+
(defn unit-to-pixel [unit-arg canvas-size]
|
45
|
+
(+ (* unit-arg (- canvas-size avatar-size)) (/ avatar-size 2)))
|
46
|
+
|
47
|
+
(defn log [& args]
|
48
|
+
(js/console.log (apply pr-str args)))
|
49
|
+
|
50
|
+
(def avatar-hover
|
51
|
+
(doto
|
52
|
+
(goog.ui/HoverCard. (js-obj)) ; svg IMAGE tags don't work here
|
53
|
+
(.setElement (dom/get-element :avatar-hover))))
|
54
|
+
|
55
|
+
(defn hide-tooltip [event]
|
56
|
+
(.setVisible avatar-hover false))
|
57
|
+
|
58
|
+
(defn attach-tooltip [img canvas-offset px py tweet]
|
59
|
+
(events/listen img events/EventType.MOUSEOUT hide-tooltip)
|
60
|
+
(events/listen
|
61
|
+
img events/EventType.MOUSEOVER
|
62
|
+
(fn [event]
|
63
|
+
(hide-tooltip event)
|
64
|
+
(.setPosition avatar-hover
|
65
|
+
(goog.ui/Tooltip.CursorTooltipPosition.
|
66
|
+
(Coordinate/sum (goog.math/Coordinate. px py)
|
67
|
+
canvas-offset)))
|
68
|
+
(dom/remove-children :avatar-hover-body)
|
69
|
+
(dom/append (dom/get-element :avatar-hover-body)
|
70
|
+
(timeline/timeline-element tweet))
|
71
|
+
(.triggerForElement avatar-hover img))))
|
72
|
+
|
73
|
+
(defn draw-graph [{:keys [locs mentions]} text]
|
74
|
+
(let [canvas-size (. g (getPixelSize))
|
75
|
+
canvas-offset (style/getPageOffset (dom/get-element :network))]
|
76
|
+
(. g (clear))
|
77
|
+
|
78
|
+
; Draw mention edges
|
79
|
+
(doseq [[username {ux1 :x, uy1 :y}] locs
|
80
|
+
:let [x1 (unit-to-pixel ux1 (.-width canvas-size))
|
81
|
+
y1 (unit-to-pixel uy1 (.-height canvas-size))]
|
82
|
+
[mention-name mention-count] (:mentions (get mentions username))]
|
83
|
+
(when-let [{ux2 :x, uy2 :y} (get locs mention-name)]
|
84
|
+
(let [x2 (unit-to-pixel ux2 (.-width canvas-size))
|
85
|
+
y2 (unit-to-pixel uy2 (.-height canvas-size))]
|
86
|
+
(.drawPath g
|
87
|
+
(-> (. g (createPath)) (.moveTo x1 y1) (.lineTo x2 y2))
|
88
|
+
edge-stroke nil))))
|
89
|
+
|
90
|
+
; Draw avatar nodes
|
91
|
+
(doseq [[username {:keys [x y] :as foo}] locs]
|
92
|
+
;(log (pr-str foo))
|
93
|
+
(let [px (- (unit-to-pixel x (.-width canvas-size)) (/ avatar-size 2))
|
94
|
+
py (- (unit-to-pixel y (.-height canvas-size)) (/ avatar-size 2))
|
95
|
+
user (get mentions username)
|
96
|
+
image-url (get user :image-url default-avatar)
|
97
|
+
img (.drawImage g px py avatar-size avatar-size image-url)]
|
98
|
+
(attach-tooltip img canvas-offset px py
|
99
|
+
{:profile_image_url image-url
|
100
|
+
:text (:last-tweet user)
|
101
|
+
:from_user (:username user)})))
|
102
|
+
|
103
|
+
(let [text (if (empty? locs)
|
104
|
+
"No locations to graph"
|
105
|
+
text)]
|
106
|
+
(when text
|
107
|
+
(.drawTextOnLine g text 5 20 (.-width canvas-size) 20
|
108
|
+
"left" font nil fill)))))
|
109
|
+
|
110
|
+
(def graph-data (atom nil))
|
111
|
+
|
112
|
+
;; Register event listeners.
|
113
|
+
|
114
|
+
(buzz/register :graph-update
|
115
|
+
(fn [data]
|
116
|
+
(reset! graph-data data)
|
117
|
+
(draw-graph (layout/radial data) nil)))
|
118
|
+
|
119
|
+
(events/listen (dom/get-element :network) events/EventType.CLICK
|
120
|
+
#(draw-graph (layout/radial @graph-data) nil))
|
121
|
+
(buzz/register :track-clicked #(. g (clear)))
|