|
| 1 | +<!DOCTYPE html> |
| 2 | +<html> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8"> |
| 5 | + <title>Background Example</title> |
| 6 | + <style media="screen"> |
| 7 | + body { |
| 8 | + font-family: Helvetica, sans-serif; |
| 9 | + display: flex; |
| 10 | + } |
| 11 | + main { |
| 12 | + order: 1; |
| 13 | + } |
| 14 | + aside { |
| 15 | + width: 300px; |
| 16 | + } |
| 17 | + aside ul { |
| 18 | + padding: 0; |
| 19 | + } |
| 20 | + aside li { |
| 21 | + list-style-type: none; |
| 22 | + margin: 10px; |
| 23 | + } |
| 24 | + aside li.active a { |
| 25 | + text-decoration: none; |
| 26 | + } |
| 27 | + iframe { |
| 28 | + border: 1px solid black; |
| 29 | + } |
| 30 | + hr:first-of-type { |
| 31 | + display: none; |
| 32 | + } |
| 33 | + /* |
| 34 | +
|
| 35 | +Atom One Light by Daniel Gamage |
| 36 | +Original One Light Syntax theme from https://github.com/atom/one-light-syntax |
| 37 | +
|
| 38 | +base: #fafafa |
| 39 | +mono-1: #383a42 |
| 40 | +mono-2: #686b77 |
| 41 | +mono-3: #a0a1a7 |
| 42 | +hue-1: #0184bb |
| 43 | +hue-2: #4078f2 |
| 44 | +hue-3: #a626a4 |
| 45 | +hue-4: #50a14f |
| 46 | +hue-5: #e45649 |
| 47 | +hue-5-2: #c91243 |
| 48 | +hue-6: #986801 |
| 49 | +hue-6-2: #c18401 |
| 50 | +
|
| 51 | +*/ |
| 52 | + |
| 53 | +.hljs { |
| 54 | + display: block; |
| 55 | + overflow-x: auto; |
| 56 | + padding: 0.5em; |
| 57 | + color: #383a42; |
| 58 | + background: #fafafa; |
| 59 | +} |
| 60 | + |
| 61 | +.hljs-comment, |
| 62 | +.hljs-quote { |
| 63 | + color: #a0a1a7; |
| 64 | + font-style: italic; |
| 65 | +} |
| 66 | + |
| 67 | +.hljs-doctag, |
| 68 | +.hljs-keyword, |
| 69 | +.hljs-formula { |
| 70 | + color: #a626a4; |
| 71 | +} |
| 72 | + |
| 73 | +.hljs-section, |
| 74 | +.hljs-name, |
| 75 | +.hljs-selector-tag, |
| 76 | +.hljs-deletion, |
| 77 | +.hljs-subst { |
| 78 | + color: #e45649; |
| 79 | +} |
| 80 | + |
| 81 | +.hljs-literal { |
| 82 | + color: #0184bb; |
| 83 | +} |
| 84 | + |
| 85 | +.hljs-string, |
| 86 | +.hljs-regexp, |
| 87 | +.hljs-addition, |
| 88 | +.hljs-attribute, |
| 89 | +.hljs-meta-string { |
| 90 | + color: #50a14f; |
| 91 | +} |
| 92 | + |
| 93 | +.hljs-built_in, |
| 94 | +.hljs-class .hljs-title { |
| 95 | + color: #c18401; |
| 96 | +} |
| 97 | + |
| 98 | +.hljs-attr, |
| 99 | +.hljs-variable, |
| 100 | +.hljs-template-variable, |
| 101 | +.hljs-type, |
| 102 | +.hljs-selector-class, |
| 103 | +.hljs-selector-attr, |
| 104 | +.hljs-selector-pseudo, |
| 105 | +.hljs-number { |
| 106 | + color: #986801; |
| 107 | +} |
| 108 | + |
| 109 | +.hljs-symbol, |
| 110 | +.hljs-bullet, |
| 111 | +.hljs-link, |
| 112 | +.hljs-meta, |
| 113 | +.hljs-selector-id, |
| 114 | +.hljs-title { |
| 115 | + color: #4078f2; |
| 116 | +} |
| 117 | + |
| 118 | +.hljs-emphasis { |
| 119 | + font-style: italic; |
| 120 | +} |
| 121 | + |
| 122 | +.hljs-strong { |
| 123 | + font-weight: bold; |
| 124 | +} |
| 125 | + |
| 126 | +.hljs-link { |
| 127 | + text-decoration: underline; |
| 128 | +} |
| 129 | + |
| 130 | + </style> |
| 131 | + </head> |
| 132 | + <body> |
| 133 | + <main> |
| 134 | + <h1>Background</h1> |
| 135 | + |
| 136 | + <iframe src="iframe.html" width="990" height="504" frameborder="1"></iframe> |
| 137 | + |
| 138 | + |
| 139 | + <hr /> |
| 140 | + <h3>Background</h3> |
| 141 | + <div class="description"><p> Part of a composition used for the background of my Elm Europe talk.</p> |
| 142 | +</div> |
| 143 | + <pre><code class="elm"><span class="hljs-keyword">module</span> Background <span class="hljs-keyword">exposing</span> (main) |
| 144 | + |
| 145 | + |
| 146 | +<span class="hljs-keyword">import</span> Color <span class="hljs-keyword">exposing</span> (<span class="hljs-type">Color</span>) |
| 147 | +<span class="hljs-keyword">import</span> Color.Convert <span class="hljs-keyword">exposing</span> (colorToCssRgb) |
| 148 | +<span class="hljs-keyword">import</span> Graph <span class="hljs-keyword">exposing</span> (<span class="hljs-type">Edge</span>, <span class="hljs-type">Graph</span>, <span class="hljs-type">Node</span>, <span class="hljs-type">NodeId</span>) |
| 149 | +<span class="hljs-keyword">import</span> IntDict |
| 150 | +<span class="hljs-keyword">import</span> List <span class="hljs-keyword">exposing</span> (range) |
| 151 | +<span class="hljs-keyword">import</span> NetworkGraphs <span class="hljs-keyword">exposing</span> (miserablesGraph, pollbooksGraph) |
| 152 | +<span class="hljs-keyword">import</span> Svg <span class="hljs-keyword">exposing</span> (..) |
| 153 | +<span class="hljs-keyword">import</span> Svg.Attributes <span class="hljs-keyword">as</span> Attr <span class="hljs-keyword">exposing</span> (..) |
| 154 | +<span class="hljs-keyword">import</span> Visualization.Force <span class="hljs-keyword">as</span> Force <span class="hljs-keyword">exposing</span> (<span class="hljs-type">State</span>) |
| 155 | +<span class="hljs-keyword">import</span> Visualization.Scale <span class="hljs-keyword">as</span> Scale <span class="hljs-keyword">exposing</span> (<span class="hljs-type">SequentialScale</span>) |
| 156 | + |
| 157 | + |
| 158 | +<span class="hljs-title">screenWidth</span> : <span class="hljs-type">Float</span> |
| 159 | +<span class="hljs-title">screenWidth</span> = |
| 160 | + <span class="hljs-number">990</span> |
| 161 | + |
| 162 | + |
| 163 | +<span class="hljs-title">screenHeight</span> : <span class="hljs-type">Float</span> |
| 164 | +<span class="hljs-title">screenHeight</span> = |
| 165 | + <span class="hljs-number">504</span> |
| 166 | + |
| 167 | + |
| 168 | +<span class="hljs-title">colorScale</span> : <span class="hljs-type">SequentialScale</span> <span class="hljs-type">Color</span> |
| 169 | +<span class="hljs-title">colorScale</span> = |
| 170 | + <span class="hljs-type">Scale</span>.sequential ( <span class="hljs-number">200</span>, <span class="hljs-number">700</span> ) <span class="hljs-type">Scale</span>.viridisInterpolator |
| 171 | + |
| 172 | + |
| 173 | +<span class="hljs-keyword">type</span> <span class="hljs-keyword">alias</span> <span class="hljs-type">CustomNode</span> = |
| 174 | + { rank : <span class="hljs-type">Int</span>, name : <span class="hljs-type">String</span> } |
| 175 | + |
| 176 | + |
| 177 | +<span class="hljs-keyword">type</span> <span class="hljs-keyword">alias</span> <span class="hljs-type">Entity</span> = |
| 178 | + <span class="hljs-type">Force</span>.<span class="hljs-type">Entity</span> <span class="hljs-type">NodeId</span> { value : <span class="hljs-type">CustomNode</span> } |
| 179 | + |
| 180 | + |
| 181 | +<span class="hljs-title">init</span> : <span class="hljs-type">Graph</span> <span class="hljs-type">Entity</span> () |
| 182 | +<span class="hljs-title">init</span> = |
| 183 | + <span class="hljs-keyword">let</span> |
| 184 | + graph = |
| 185 | + <span class="hljs-type">Graph</span>.mapContexts |
| 186 | + (\({ node, incoming, outgoing } <span class="hljs-keyword">as</span> ctx) -> |
| 187 | + { ctx | node = { label = <span class="hljs-type">Force</span>.entity node.id (<span class="hljs-type">CustomNode</span> (<span class="hljs-type">IntDict</span>.size incoming + <span class="hljs-type">IntDict</span>.size outgoing) node.label), id = node.id } } |
| 188 | + ) |
| 189 | + miserablesGraph |
| 190 | + |
| 191 | + links = |
| 192 | + graph |
| 193 | + |> <span class="hljs-type">Graph</span>.edges |
| 194 | + |> <span class="hljs-type">List</span>.map (\{ from, to } -> { source = from, target = to, distance = <span class="hljs-number">30</span>, strength = <span class="hljs-type">Nothing</span> }) |
| 195 | + |
| 196 | + forces = |
| 197 | + [ <span class="hljs-type">Force</span>.customLinks <span class="hljs-number">1</span> links |
| 198 | + , <span class="hljs-type">Force</span>.manyBodyStrength <span class="hljs-number">-30</span> <| <span class="hljs-type">List</span>.map .id <| <span class="hljs-type">Graph</span>.nodes graph |
| 199 | + , <span class="hljs-type">Force</span>.center (screenWidth / <span class="hljs-number">2</span>) (screenHeight / <span class="hljs-number">2</span>) |
| 200 | + ] |
| 201 | + <span class="hljs-keyword">in</span> |
| 202 | + updateGraphWithList graph (<span class="hljs-type">Force</span>.computeSimulation (<span class="hljs-type">Force</span>.simulation forces) <| <span class="hljs-type">List</span>.map .label <| <span class="hljs-type">Graph</span>.nodes graph) |
| 203 | + |
| 204 | + |
| 205 | +<span class="hljs-title">updateGraphWithList</span> : <span class="hljs-type">Graph</span> <span class="hljs-type">Entity</span> () -> <span class="hljs-type">List</span> <span class="hljs-type">Entity</span> -> <span class="hljs-type">Graph</span> <span class="hljs-type">Entity</span> () |
| 206 | +<span class="hljs-title">updateGraphWithList</span> = |
| 207 | + <span class="hljs-keyword">let</span> |
| 208 | + graphUpdater value = |
| 209 | + <span class="hljs-type">Maybe</span>.map (\ctx -> updateContextWithValue ctx value) |
| 210 | + <span class="hljs-keyword">in</span> |
| 211 | + <span class="hljs-type">List</span>.foldr (\node graph -> <span class="hljs-type">Graph</span>.update node.id (graphUpdater node) graph) |
| 212 | + |
| 213 | + |
| 214 | +<span class="hljs-title">updateContextWithValue</span> nodeCtx value = |
| 215 | + <span class="hljs-keyword">let</span> |
| 216 | + node = |
| 217 | + nodeCtx.node |
| 218 | + <span class="hljs-keyword">in</span> |
| 219 | + { nodeCtx | node = { node | label = value } } |
| 220 | + |
| 221 | + |
| 222 | +<span class="hljs-title">linkElement</span> : <span class="hljs-type">Graph</span> <span class="hljs-type">Entity</span> () -> <span class="hljs-type">Edge</span> () -> <span class="hljs-type">Svg</span> msg |
| 223 | +<span class="hljs-title">linkElement</span> graph edge = |
| 224 | + <span class="hljs-keyword">let</span> |
| 225 | + retrieveEntity = |
| 226 | + <span class="hljs-type">Maybe</span>.withDefault (<span class="hljs-type">Force</span>.entity <span class="hljs-number">0</span> (<span class="hljs-type">CustomNode</span> <span class="hljs-number">0</span> <span class="hljs-string">""</span>)) << <span class="hljs-type">Maybe</span>.map (.node >> .label) |
| 227 | + |
| 228 | + source = |
| 229 | + retrieveEntity <| <span class="hljs-type">Graph</span>.get edge.from graph |
| 230 | + |
| 231 | + target = |
| 232 | + retrieveEntity <| <span class="hljs-type">Graph</span>.get edge.to graph |
| 233 | + <span class="hljs-keyword">in</span> |
| 234 | + line |
| 235 | + [ strokeWidth <span class="hljs-string">"1"</span> |
| 236 | + , stroke <| colorToCssRgb <| <span class="hljs-type">Scale</span>.convert colorScale source.x |
| 237 | + , x1 (toString source.x) |
| 238 | + , y1 (toString source.y) |
| 239 | + , x2 (toString target.x) |
| 240 | + , y2 (toString target.y) |
| 241 | + ] |
| 242 | + [] |
| 243 | + |
| 244 | + |
| 245 | +<span class="hljs-title">hexagon</span> ( x, y ) size attrs = |
| 246 | + <span class="hljs-keyword">let</span> |
| 247 | + angle = |
| 248 | + <span class="hljs-number">2</span> * pi / <span class="hljs-number">6</span> |
| 249 | + |
| 250 | + p = |
| 251 | + range <span class="hljs-number">0</span> <span class="hljs-number">6</span> |
| 252 | + |> <span class="hljs-type">List</span>.map toFloat |
| 253 | + |> <span class="hljs-type">List</span>.map (\a -> ( x + (cos (a * angle)) * size, y + (sin (a * angle)) * size )) |
| 254 | + |> <span class="hljs-type">List</span>.map (\( x, y ) -> toString x ++ <span class="hljs-string">","</span> ++ toString y) |
| 255 | + |> <span class="hljs-type">String</span>.join <span class="hljs-string">" "</span> |
| 256 | + |> points |
| 257 | + <span class="hljs-keyword">in</span> |
| 258 | + polygon |
| 259 | + (p :: attrs) |
| 260 | + |
| 261 | + |
| 262 | +<span class="hljs-title">nodeSize</span> size node = |
| 263 | + hexagon ( node.x, node.y ) |
| 264 | + size |
| 265 | + [ fill <| colorToCssRgb <| <span class="hljs-type">Scale</span>.convert colorScale node.x |
| 266 | + ] |
| 267 | + [ <span class="hljs-type">Svg</span>.title [] [ text node.value.name ] ] |
| 268 | + |
| 269 | + |
| 270 | +<span class="hljs-title">nodeElement</span> node = |
| 271 | + <span class="hljs-keyword">if</span> node.label.value.rank < <span class="hljs-number">5</span> <span class="hljs-keyword">then</span> |
| 272 | + nodeSize <span class="hljs-number">4</span> node.label |
| 273 | + <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.label.value.rank < <span class="hljs-number">9</span> <span class="hljs-keyword">then</span> |
| 274 | + nodeSize <span class="hljs-number">7</span> node.label |
| 275 | + <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.label.value.rank % <span class="hljs-number">2</span> == <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> |
| 276 | + g [] |
| 277 | + [ nodeSize <span class="hljs-number">9</span> node.label |
| 278 | + , circle |
| 279 | + [ r <span class="hljs-string">"12"</span> |
| 280 | + , cx <| toString node.label.x |
| 281 | + , cy <| toString node.label.y |
| 282 | + , fill <span class="hljs-string">"none"</span> |
| 283 | + , stroke <| colorToCssRgb <| <span class="hljs-type">Scale</span>.convert colorScale node.label.x |
| 284 | + ] |
| 285 | + [] |
| 286 | + ] |
| 287 | + <span class="hljs-keyword">else</span> |
| 288 | + nodeSize <span class="hljs-number">10</span> node.label |
| 289 | + |
| 290 | + |
| 291 | +<span class="hljs-title">view</span> model = |
| 292 | + svg [ width (toString screenWidth ++ <span class="hljs-string">"px"</span>), height (toString screenHeight ++ <span class="hljs-string">"px"</span>) ] |
| 293 | + [ g [ class <span class="hljs-string">"links"</span> ] <| <span class="hljs-type">List</span>.map (linkElement model) <| <span class="hljs-type">Graph</span>.edges model |
| 294 | + , g [ class <span class="hljs-string">"nodes"</span> ] <| <span class="hljs-type">List</span>.map nodeElement <| <span class="hljs-type">Graph</span>.nodes model |
| 295 | + ] |
| 296 | + |
| 297 | + |
| 298 | +<span class="hljs-title">main</span> = |
| 299 | + init |> view |
| 300 | +</code></pre> |
| 301 | + |
| 302 | + <hr /> |
| 303 | + <h3></h3> |
| 304 | + <div class="description"></div> |
| 305 | + <pre><code class="elm"></code></pre> |
| 306 | + |
| 307 | + </main> |
| 308 | + <aside> |
| 309 | + <h2>Examples</h2> |
| 310 | + <ul> |
| 311 | + |
| 312 | + <li class="active"> |
| 313 | + <a href="../Background">Background</a> |
| 314 | + </li> |
| 315 | + |
| 316 | + <li > |
| 317 | + <a href="../Centroid">Centroid</a> |
| 318 | + </li> |
| 319 | + |
| 320 | + <li > |
| 321 | + <a href="../CornerRadius">CornerRadius</a> |
| 322 | + </li> |
| 323 | + |
| 324 | + <li > |
| 325 | + <a href="../Cross">Cross</a> |
| 326 | + </li> |
| 327 | + |
| 328 | + <li > |
| 329 | + <a href="../Curves">Curves</a> |
| 330 | + </li> |
| 331 | + |
| 332 | + <li > |
| 333 | + <a href="../CustomPieChart">CustomPieChart</a> |
| 334 | + </li> |
| 335 | + |
| 336 | + <li > |
| 337 | + <a href="../ForceDirectedGraph">ForceDirectedGraph</a> |
| 338 | + </li> |
| 339 | + |
| 340 | + <li > |
| 341 | + <a href="../LineChart">LineChart</a> |
| 342 | + </li> |
| 343 | + |
| 344 | + <li > |
| 345 | + <a href="../PadAngle">PadAngle</a> |
| 346 | + </li> |
| 347 | + |
| 348 | + <li > |
| 349 | + <a href="../Petals">Petals</a> |
| 350 | + </li> |
| 351 | + |
| 352 | + <li > |
| 353 | + <a href="../PieChart">PieChart</a> |
| 354 | + </li> |
| 355 | + |
| 356 | + </ul> |
| 357 | + </aside> |
| 358 | + </body> |
| 359 | +</html> |
0 commit comments