clementine 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -2
  3. data/LICENSE.txt +22 -0
  4. data/README.md +11 -6
  5. data/Rakefile +22 -0
  6. data/clementine.gemspec +2 -1
  7. data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
  8. data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
  9. data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
  10. data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
  11. data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
  12. data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
  13. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
  14. data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
  15. data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
  16. data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
  17. data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
  18. data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
  19. data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
  20. data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
  21. data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
  22. data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
  23. data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
  24. data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
  25. data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
  26. data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
  27. data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
  28. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
  29. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
  30. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
  31. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
  32. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
  33. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
  34. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
  35. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
  36. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
  37. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
  38. data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
  39. data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
  40. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
  41. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
  42. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
  43. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
  44. data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
  45. data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
  46. data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
  47. data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
  48. data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
  49. data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
  50. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
  51. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
  52. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
  53. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
  54. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
  55. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
  56. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
  57. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
  58. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
  59. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
  60. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
  61. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
  62. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
  63. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
  64. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
  65. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
  66. data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
  67. data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
  68. data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
  69. data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
  70. data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
  71. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
  72. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
  73. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
  74. data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
  75. data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
  76. data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
  77. data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
  78. data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
  79. data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
  80. data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
  81. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
  82. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
  83. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
  84. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
  85. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
  86. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
  87. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
  88. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
  89. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
  90. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
  91. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
  92. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
  93. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
  94. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
  95. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
  96. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
  97. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
  98. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
  99. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
  100. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
  101. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
  102. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
  103. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
  104. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
  105. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
  106. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
  107. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
  108. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
  109. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
  110. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
  111. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
  112. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
  113. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
  114. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
  115. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
  116. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
  117. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
  118. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
  119. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
  120. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
  121. data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
  122. data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
  123. data/lib/clementine.rb +3 -24
  124. data/lib/clementine/clojurescript_engine.rb +9 -48
  125. data/lib/clementine/clojurescript_engine/base.rb +15 -0
  126. data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
  127. data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
  128. data/lib/clementine/version.rb +1 -1
  129. data/test/clojurescript_engine_test.rb +36 -14
  130. metadata +177 -83
  131. data/vendor/assets/lib/clojure.jar +0 -0
  132. data/vendor/assets/lib/compiler.jar +0 -0
  133. data/vendor/assets/lib/goog.jar +0 -0
  134. data/vendor/assets/lib/js.jar +0 -0
  135. data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
  136. data/vendor/assets/src/clj/cljs/core.clj +0 -702
  137. data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
  138. data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
  139. 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)))