Commits: 8
Merge Dots and Line into more general Shapes example
index d67a0ae..4659dcb 100644
--- a/content/day-1.txt
+++ b/content/day-1.txt
@@ -111,7 +111,7 @@ This was a warmup. Let's try something more challenging.
=We want to display a dot at the center of the screen, like this:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= viewBox = -300 -300 600 600
@@ -201,7 +201,7 @@ Start the reactor again by entering:
=Reload the browser. You should see something like this:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= fill = False
@@ -236,7 +236,7 @@ First we have to realize that the dot is inside an {Code|svg} element that itsel
=Reloading the browser should reveal something like this:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = pink
= fill = False
@@ -295,7 +295,7 @@ As before, press {Key|enter} to follow the plan. Now let's use the package. Chan
=Reload the browser. The SVG space now fills the entire viewport. Even the small white margin is gone!
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = pink
= fill = True
@@ -364,7 +364,7 @@ To change the position of the dot, we can use the {Code|cx} and {Code|cy} attrib
= ]
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= fill = True
@@ -451,7 +451,7 @@ In the code we set the viewbox as an attribute of the {Code|svg} element, like t
=There are only two changes here. First we reset the {Code|cx} and {Code|cy} attributes of the {Code|circle} back to {Code|"0"} (on lines 11 and 12). We want the dot to be back at origin. Then we set up the position of the viewbox on line 20. Try experimenting with different values. If you set them right and refresh the browser the dot should be in the center of the screen.
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = pink
= fill = True
@@ -501,7 +501,7 @@ Speaking of colors, now that we've centered our dot, it's time to give it a colo
=The only change is on line 13. Reload the browser and see this:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= fill = Trueindex d0a4ad1..1073983 100644
--- a/content/day-2.txt
+++ b/content/day-2.txt
@@ -81,7 +81,7 @@ If you look closely in your source code, the block above is surrounded by {Code|
=Now the list spans from lines 9 to 23 and contains two items: skyblue and orange dots. The result should be:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= fill = True
@@ -139,7 +139,7 @@ Oh oh! The list contains two dots, but we can only see the orange one on the scr
=Now you should see this:
=
=| Window
- | Dots
+ | Shapes
= | Container
= background = none
= fill = True
@@ -223,7 +223,7 @@ The {Code|r} attribute stands for radius. Then it was basically dictating the si
= radius = 80
=
=| Row
- | Dots
+ | Shapes
= | Container
= background = none
= fill = True
@@ -235,7 +235,7 @@ The {Code|r} attribute stands for radius. Then it was basically dictating the si
= cy = 0
= color = skyblue
=
- | Dots
+ | Shapes
= | Container
= background = none
= fill = True
@@ -247,7 +247,7 @@ The {Code|r} attribute stands for radius. Then it was basically dictating the si
= cy = 0
= color = skyblue
=
- | Dots
+ | Shapes
= | Container
= background = none
= fill = Trueindex 94e0a3f..4db325b 100644
--- a/src/Examples.elm
+++ b/src/Examples.elm
@@ -3,12 +3,11 @@ module Examples exposing (Model, Msg(..), init, subscriptions, update)
=import Examples.CartesianCoordinates
=import Examples.Circle
=import Examples.Counter
-import Examples.Dots
=import Examples.Gradient
-import Examples.Line
=import Examples.NestedTransformations
=import Examples.PolarCoordinates
=import Examples.RosetteTypedTransformations
+import Examples.Shapes
=import Examples.Spiral
=import Examples.Transformations
=import Examples.Treedeleted file mode 100644
index 4285cb8..0000000
--- a/src/Examples/Dots.elm
+++ /dev/null
@@ -1,106 +0,0 @@
-module Examples.Dots exposing
- ( Config
- , Container
- , Dot
- , main
- , ui
- )
-
-import Circle2d
-import Element exposing (Element)
-import Geometry.Svg
-import Html exposing (Html)
-import Html.Attributes
-import Point2d exposing (Point2d)
-import Svg exposing (Attribute, Svg)
-import Svg.Attributes
-
-
-type alias Config =
- { container : Container
- , dots : List Dot
- }
-
-
-type alias Container =
- { background : String
- , viewBox : String
- , fill : Bool
- }
-
-
-type alias Dot =
- { cx : Float
- , cy : Float
- , radius : Float
- , color : String
- }
-
-
-defaults : Config
-defaults =
- { container =
- { background = "none"
- , viewBox = "-300 -300 600 600"
- , fill = True
- }
- , dots =
- [ { cx = 0
- , cy = 0
- , radius = 10
- , color = "skyblue"
- }
- ]
- }
-
-
-main : Html msg
-main =
- ui defaults
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
-
-
-ui : Config -> Element msg
-ui { container, dots } =
- let
- dot : Dot -> Svg msg
- dot { cx, cy, color, radius } =
- ( cx, cy )
- |> Point2d.fromCoordinates
- |> Circle2d.withRadius radius
- |> Geometry.Svg.circle2d [ Svg.Attributes.fill color ]
-
- width =
- if container.fill then
- "100%"
-
- else
- "300"
-
- height =
- if container.fill then
- "100%"
-
- else
- "150"
-
- padding =
- if container.fill then
- "0"
-
- else
- "5px"
- in
- dots
- |> List.map dot
- |> Svg.svg
- [ Svg.Attributes.viewBox container.viewBox
- , Html.Attributes.style "background" container.background
- , Svg.Attributes.width width
- , Svg.Attributes.height height
- , Html.Attributes.style "margin" padding
- ]
- |> Element.htmldeleted file mode 100644
index d105ef5..0000000
--- a/src/Examples/Line.elm
+++ /dev/null
@@ -1,29 +0,0 @@
-module Examples.Line exposing (main, ui)
-
-import Element
-import Svg
-import Svg.Attributes
-
-
-main =
- Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
- ui
-
-
-ui =
- Element.html
- (Svg.svg
- [ Svg.Attributes.height "200"
- , Svg.Attributes.viewBox "-10 -25 100 100"
- ]
- [ Svg.line
- [ Svg.Attributes.x2 "1"
- , Svg.Attributes.stroke "black"
- , Svg.Attributes.transform "rotate(30) scale(100, 1)"
- ]
- []
- ]
- )new file mode 100644
index 0000000..485e44b
--- /dev/null
+++ b/src/Examples/Shapes.elm
@@ -0,0 +1,187 @@
+module Examples.Shapes exposing
+ ( Config
+ , Container
+ , Shape(..)
+ , main
+ , ui
+ )
+
+import Circle2d
+import Element exposing (Element)
+import Geometry.Svg
+import Html exposing (Html)
+import Html.Attributes
+import LineSegment2d
+import Point2d exposing (Point2d)
+import Svg exposing (Attribute, Svg)
+import Svg.Attributes
+import Transformations
+
+
+type alias Config =
+ { container : Container
+ , shapes : List Shape
+ }
+
+
+type alias Container =
+ { background : String
+ , viewBox : String
+ , fill : Bool
+ }
+
+
+type Shape
+ = Dot
+ { cx : Float
+ , cy : Float
+ , radius : Float
+ , color : String
+ }
+ | Line
+ { x1 : Float
+ , y1 : Float
+ , x2 : Float
+ , y2 : Float
+ , color : String
+ }
+ | Group
+ { rotation : Float
+ , x : Float
+ , y : Float
+ }
+ (List Shape)
+
+
+defaults : Config
+defaults =
+ { container =
+ { background = "none"
+ , viewBox = "-300 -300 600 600"
+ , fill = True
+ }
+ , shapes =
+ [ Dot
+ { cx = 0
+ , cy = 0
+ , radius = 10
+ , color = "skyblue"
+ }
+ , Line
+ { x1 = 0.0
+ , y1 = 0.0
+ , x2 = 20.0
+ , y2 = 30.0
+ , color = "green"
+ }
+ , Group { rotation = -45.0, x = 0.0, y = 0.0 }
+ [ Line
+ { x1 = 20.0
+ , y1 = 0.0
+ , x2 = 70.0
+ , y2 = 0.0
+ , color = "orange"
+ }
+ , Dot
+ { cx = 100
+ , cy = 0.0
+ , radius = 20.0
+ , color = "red"
+ }
+ , Group { rotation = -45.0, x = 100.0, y = 0.0 }
+ [ Line
+ { x1 = 20.0
+ , y1 = 0.0
+ , x2 = 70.0
+ , y2 = 0.0
+ , color = "orange"
+ }
+ , Dot
+ { cx = 100
+ , cy = 0.0
+ , radius = 20.0
+ , color = "red"
+ }
+ ]
+ ]
+ ]
+ }
+
+
+main : Html msg
+main =
+ ui defaults
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ui : Config -> Element msg
+ui { container, shapes } =
+ let
+ shape : Shape -> Svg msg
+ shape s =
+ case s of
+ Dot { cx, cy, color, radius } ->
+ ( cx, cy )
+ |> Point2d.fromCoordinates
+ |> Circle2d.withRadius radius
+ |> Geometry.Svg.circle2d [ Svg.Attributes.fill color ]
+
+ Line { x1, y1, x2, y2, color } ->
+ let
+ a =
+ Point2d.fromCoordinates ( x1, y1 )
+
+ b =
+ Point2d.fromCoordinates ( x2, y2 )
+ in
+ LineSegment2d.from a b
+ |> Geometry.Svg.lineSegment2d
+ [ Svg.Attributes.stroke color
+ , Svg.Attributes.strokeWidth "3"
+ ]
+
+ Group { rotation, x, y } ss ->
+ ss
+ |> List.map shape
+ |> Svg.g
+ [ [ Transformations.Rotate rotation
+ , Transformations.Translate x y
+ ]
+ |> Transformations.apply
+ |> Svg.Attributes.transform
+ ]
+
+ width =
+ if container.fill then
+ "100%"
+
+ else
+ "300"
+
+ height =
+ if container.fill then
+ "100%"
+
+ else
+ "150"
+
+ padding =
+ if container.fill then
+ "0"
+
+ else
+ "5px"
+ in
+ shapes
+ |> List.map shape
+ |> Svg.svg
+ [ Svg.Attributes.viewBox container.viewBox
+ , Html.Attributes.style "background" container.background
+ , Svg.Attributes.width width
+ , Svg.Attributes.height height
+ , Html.Attributes.style "margin" padding
+ ]
+ |> Element.htmlindex bf183c7..ec3938a 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -23,13 +23,12 @@ import Examples
=import Examples.CartesianCoordinates
=import Examples.Circle
=import Examples.Counter
-import Examples.Dots
=import Examples.Gradient
-import Examples.Line
=import Examples.NestedTransformations
=import Examples.PolarCoordinates
=import Examples.Protractor
=import Examples.RosetteTypedTransformations
+import Examples.Shapes
=import Examples.Spiral
=import Examples.Transformations
=import Examples.Tree
@@ -681,10 +680,9 @@ document =
=
= examples =
= [ counter
- , dots
+ , shapes
= , circle
= , protractor
- , line
= , gradient
= , transformations
= , nestedTransformations
@@ -731,39 +729,81 @@ document =
= in
= Mark.stub "Counter" render
=
- dots : Mark.Block (Examples.Model -> Element Msg)
- dots =
+ shapes : Mark.Block (Examples.Model -> Element Msg)
+ shapes =
= let
= render :
- Examples.Dots.Config
+ Examples.Shapes.Config
= -> Examples.Model
= -> Element Msg
= render config model =
- Examples.Dots.ui config
+ Examples.Shapes.ui config
=
- container : Mark.Block Examples.Dots.Container
+ container : Mark.Block Examples.Shapes.Container
= container =
= Mark.record3 "Container"
- Examples.Dots.Container
+ Examples.Shapes.Container
= (Mark.field "background" Mark.string)
= (Mark.field "viewBox" Mark.string)
= (Mark.field "fill" Mark.bool)
=
- dot : Mark.Block Examples.Dots.Dot
+ dot : Mark.Block Examples.Shapes.Shape
= dot =
= Mark.record4 "Dot"
- Examples.Dots.Dot
+ (\cx cy radius color ->
+ Examples.Shapes.Dot
+ { cx = cx
+ , cy = cy
+ , radius = radius
+ , color = color
+ }
+ )
= (Mark.field "cx" Mark.float)
= (Mark.field "cy" Mark.float)
= (Mark.field "radius" Mark.float)
= (Mark.field "color" Mark.string)
+
+ line : Mark.Block Examples.Shapes.Shape
+ line =
+ Mark.record5 "Line"
+ (\x1 y1 x2 y2 color ->
+ Examples.Shapes.Line
+ { x1 = x1
+ , y1 = y1
+ , x2 = x2
+ , y2 = y2
+ , color = color
+ }
+ )
+ (Mark.field "x1" Mark.float)
+ (Mark.field "y1" Mark.float)
+ (Mark.field "x2" Mark.float)
+ (Mark.field "y2" Mark.float)
+ (Mark.field "color" Mark.string)
+
+ -- TODO: Implement a recursive group block (that can contain nested groups)
+ group : Mark.Block Examples.Shapes.Shape
+ group =
+ Mark.record4 "Group"
+ (\x y rotation children ->
+ Examples.Shapes.Group
+ { x = x
+ , y = y
+ , rotation = rotation
+ }
+ children
+ )
+ (Mark.field "x" Mark.float)
+ (Mark.field "y" Mark.float)
+ (Mark.field "rotation" Mark.float)
+ (Mark.field "children" (Mark.manyOf [ dot, line ]))
= in
- Mark.block "Dots"
+ Mark.block "Shapes"
= render
= (Mark.startWith
- Examples.Dots.Config
+ Examples.Shapes.Config
= container
- (Mark.manyOf [ dot ])
+ (Mark.manyOf [ dot, line, group ])
= )
=
= circle : Mark.Block (Examples.Model -> Element Msg)
@@ -784,18 +824,6 @@ document =
= (Mark.field "scatter" Mark.bool)
= |> Mark.map render
=
- line : Mark.Block (Examples.Model -> Element Msg)
- line =
- let
- render model =
- Examples.Line.ui
- |> Element.el
- [ Element.height (Element.px 400)
- , Element.width Element.fill
- ]
- in
- Mark.stub "Line" render
-
= gradient : Mark.Block (Examples.Model -> Element Msg)
= gradient =
= letProvide a connected dots example on day 3
index 155a00b..8975942 100644
--- a/content/day-3.txt
+++ b/content/day-3.txt
@@ -621,8 +621,102 @@ Once you have the function defined, let's use it. For every dot, create one line
=
=You should see something like this in the browser:
=
-| Monospace
- TODO: Example showing the connected dots
+| Window
+ | Shapes
+ | Container
+ background = none
+ fill = True
+ viewBox = -100 -100 200 200
+
+ | Group
+ x = 0
+ y = 0
+ rotation = 0
+ children =
+ | Line
+ x1 = 0
+ y1 = 0
+ x2 = 80
+ y2 = 0
+ color = skyblue
+
+ | Dot
+ cx = 80
+ cy = 0
+ radius = 10
+ color = skyblue
+
+ | Group
+ x = 0
+ y = 0
+ rotation = 72
+ children =
+ | Line
+ x1 = 0
+ y1 = 0
+ x2 = 80
+ y2 = 0
+ color = orange
+
+ | Dot
+ cx = 80
+ cy = 0
+ radius = 10
+ color = orange
+
+ | Group
+ x = 0
+ y = 0
+ rotation = 144
+ children =
+ | Line
+ x1 = 0
+ y1 = 0
+ x2 = 80
+ y2 = 0
+ color = red
+
+ | Dot
+ cx = 80
+ cy = 0
+ radius = 10
+ color = red
+
+ | Group
+ x = 0
+ y = 0
+ rotation = 216
+ children =
+ | Line
+ x1 = 0
+ y1 = 0
+ x2 = 80
+ y2 = 0
+ color = lime
+
+ | Dot
+ cx = 80
+ cy = 0
+ radius = 10
+ color = lime
+
+ | Group
+ x = 0
+ y = 0
+ rotation = 288
+ children =
+ | Line
+ x1 = 0
+ y1 = 0
+ x2 = 80
+ y2 = 0
+ color = maroon
+
+ | Dot
+ cx = 80
+ cy = 0
+ radius = 10
+ color = maroon
=
=| Emphasize
= Congratulations!index 485e44b..76067a3 100644
--- a/src/Examples/Shapes.elm
+++ b/src/Examples/Shapes.elm
@@ -140,7 +140,7 @@ ui { container, shapes } =
= LineSegment2d.from a b
= |> Geometry.Svg.lineSegment2d
= [ Svg.Attributes.stroke color
- , Svg.Attributes.strokeWidth "3"
+ , Svg.Attributes.strokeWidth "1"
= ]
=
= Group { rotation, x, y } ss ->WIP add Editor block to Code block.
Correct typos.
index d67a0ae..dbba549 100644
--- a/content/day-1.txt
+++ b/content/day-1.txt
@@ -79,14 +79,18 @@ Just press {Key|enter} once again to proceed. Then to create the file which will
=
=It may take few seconds, but eventually this command should open a new Atom editor window with an empty text file. If you prefer to use different editor, feel free to do so. Once the editor is ready, type the code below and save the file.
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
+ | Code
+ module Main exposing (main)
=
- import Html
=
- main =
- Html.text "Hello, Tree"
+ import Html
+
+ main =
+ Html.text "Hello, Tree"
=
=Then switch back to the terminal and enter the following command:
=
@@ -126,31 +130,35 @@ We want to display a dot at the center of the screen, like this:
=
=Below is the complete code to draw a dot like this, but don't type it in your editor yet! We are going to recreate it together, step by step.
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Element
+ import Svg
+ import Svg.Attributes
=
- main =
- Svg.svg
- [ Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.color "skyblue"
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- []
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.color "skyblue"
+ ]
+ []
= ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=We are going to use a technology called *SVG (Scalable Vector Graphics)*. It's all about drawing shapes on the screen. Let's install an Elm Package to help us work with SVG. Stop the reactor running in the terminal by pressing {Key|ctrl} + {Key|c} and then enter the following command:
=
@@ -177,18 +185,22 @@ In response you should see something like this:
=
=Press {Key|enter} to proceed with the installation. Now that we have {Code|elm//svg} installed, we can write the code that will draw a dot for us. Change the code to look like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Svg
+ import Svg.Attributes
=
- main =
- Svg.svg []
- [ Svg.circle
- [ Svg.Attributes.r "10" ] []
- ]
+
+ main =
+ Svg.svg []
+ [ Svg.circle
+ [ Svg.Attributes.r "10" ] []
+ ]
=
=Start the reactor again by entering:
=
@@ -219,19 +231,23 @@ It's a good start, but the dot is not in the center of the screen yet. Let's try
=
=First we have to realize that the dot is inside an {Code|svg} element that itself has a position, width and height. We can make the background of the {Code|svg} element pink to see where it is:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Svg
+ import Svg.Attributes
=
- main =
- Svg.svg [ Svg.Attributes.style "background: pink" ]
- [ Svg.circle
- [ Svg.Attributes.r "10" ]
- []
- ]
+
+ main =
+ Svg.svg [ Svg.Attributes.style "background: pink" ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10" ]
+ []
+ ]
=
=Reloading the browser should reveal something like this:
=
@@ -257,30 +273,34 @@ To do this we will use a package called {Code|mdgriffith//elm-ui}. It makes layi
=
=As before, press {Key|enter} to follow the plan. Now let's use the package. Change the code to look like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Element
+ import Svg
+ import Svg.Attributes
=
- main =
- Svg.svg
- [ Svg.Attributes.style "background: pink"
- , Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- ]
- [ Svg.circle
- [ Svg.Attributes.r "10"
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.style "background: pink"
+ , Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
= ]
- []
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ ]
+ []
= ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=
=| Note
@@ -336,32 +356,40 @@ Initially the center of the dot is at a point called /the origin/ or {Code|\{ x
=
=To change the position of the dot, we can use the {Code|cx} and {Code|cy} attributes of the {Code|circle} element, like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 11
+ left = 8
+ width = 25
+ height = 2
=
- import Element
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Element
+ import Svg
+ import Svg.Attributes
=
- main =
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "100"
- , Svg.Attributes.cy "50"
- ]
- []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: pink"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "100"
+ , Svg.Attributes.cy "50"
+ ]
+ []
= ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: pink"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=| Window
= | Dots
@@ -395,7 +423,7 @@ Fortunately, we don't need to know the width and height of the {Code|svg} elemen
=
=You can imagine an SVG element as an infinite surface on which elements are placed. Which elements you see, depends on where you look. And where you look is called the *viewbox*. It has four properties: {Code|top}, {Code|left}, {Code|width} and {Code|height}.
=
-It works a little bit like a photo camera pointing directly at the surface. You can move it up, down (along the {Code|y} axis) and left and right (along the {Code|x} axis). You can also change it's focal length to cover more or less area. Unlike a lens of the camera you set the width and height separately. If you set it so that the dot is in the middle of your frame, then no matter how big the print of the picture will be, the dot will always be in the center. Increasing the {Code|width} and {Code|height} of the viewbox will make more of the surrounding surface visible and the dot will become smaller, but it's position won't change. Let's see it in action:
+It works a little bit like a photo camera pointing directly at the surface. You can move it up, down (along the {Code|y} axis) and left and right (along the {Code|x} axis). You can also change its focal length to cover more or less area. Unlike a lens of the camera you set the width and height separately. If you set it so that the dot is in the middle of your frame, then no matter how big the print of the picture will be, the dot will always be in the center. Increasing the {Code|width} and {Code|height} of the viewbox will make more of the surrounding surface visible and the dot will become smaller, but it's position won't change. Let's see it in action:
=
=| Row
= | ViewBox
@@ -420,33 +448,51 @@ So instead of moving the dot in the SVG plane, we change where we look by moving
=
=In the code we set the viewbox as an attribute of the {Code|svg} element, like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 20
+ left = 8
+ width = 44
+ height = 1
=
- import Element
- import Svg
- import Svg.Attributes
+ | Highlight
+ top = 11
+ left = 8
+ width = 23
+ height = 2
=
+ | Fold
+ start = 1
+ length = 7
=
- main =
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- ]
- []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: pink"
- , Svg.Attributes.viewBox "-300 -300 600 600"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ ]
+ []
= ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: pink"
+ , Svg.Attributes.viewBox "-300 -300 600 600"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=There are only two changes here. First we reset the {Code|cx} and {Code|cy} attributes of the {Code|circle} back to {Code|"0"} (on lines 11 and 12). We want the dot to be back at origin. Then we set up the position of the viewbox on line 20. Try experimenting with different values. If you set them right and refresh the browser the dot should be in the center of the screen.
=
@@ -470,33 +516,49 @@ You can also remove line 19 to remove the pink background, or set it to some oth
=
=Speaking of colors, now that we've centered our dot, it's time to give it a color! We do it by adding a {Code|fill} attribute to the {Code|circle} element, like that:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 13
+ left = 8
+ width = 31
+ height = 1
=
- import Element
- import Svg
- import Svg.Attributes
+ | Fold
+ start = 1
+ length = 7
=
+ | Fold
+ start = 17
+ length = 12
=
- main =
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.viewBox "-300 -300 600 600"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
= ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.viewBox "-300 -300 600 600"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=The only change is on line 13. Reload the browser and see this:
=index d0a4ad1..9c0d915 100644
--- a/content/day-2.txt
+++ b/content/day-2.txt
@@ -43,40 +43,52 @@ First obvious difference is that now we have multiple dots. The only dot we have
=
=If you look closely in your source code, the block above is surrounded by {Code|[} and {Code|]} characters. That's a list. We will talk about lists during the next day. For now it's enough to say that a list can contain zero, one or more items of the same type. In this case it contains one item of type {Code|Svg msg} - our lonely, blue dot. Let's add a second one like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg
- import Svg.Attributes
+ | Fold
+ start = 1
+ length = 7
=
+ | Fold
+ start = 24
+ length = 12
=
- main =
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- ]
- []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.viewBox "-300 -300 600 600"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ ]
+ []
= ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.viewBox "-300 -300 600 600"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Now the list spans from lines 9 to 23 and contains two items: skyblue and orange dots. The result should be:
=
@@ -101,40 +113,56 @@ Now the list spans from lines 9 to 23 and contains two items: skyblue and orange
=
=Oh oh! The list contains two dots, but we can only see the orange one on the screen. Where is the blue one? It's behind the orange. Recall how the cartesian coordinates work: if {Code|x} and {Code|y} of the center are the same, then the dots are in the same place. If we want to see both dots, let's move one of them to a different place, like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 18
+ left = 8
+ width = 24
+ height = 1
=
- import Element
- import Svg
- import Svg.Attributes
+ | Fold
+ start = 1
+ length = 7
=
+ | Fold
+ start = 24
+ length = 12
=
- main =
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "50"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- ]
- []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.viewBox "-300 -300 600 600"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "50"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ ]
+ []
= ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.viewBox "-300 -300 600 600"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Now you should see this:
=
@@ -205,10 +233,14 @@ We can say that dots lay on a circle, if the distance to the center is the same
=
=We call this distance /a *radius* of a circle/. We already saw radius used as an attribute of a circle when we were making our first dot. Remember:
=
-| Code
- Svg.circle
- [ Svg.Attributes.r "10"]
- []
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ Svg.circle
+ [ Svg.Attributes.r "10"]
+ []
=
=The {Code|r} attribute stands for radius. Then it was basically dictating the size of the dot. The larger the radius the bigger the circle. A dot is just a filled circle!
=
@@ -424,30 +456,34 @@ Now that we understand what it means to be placed on a circle and evenly distrib
=
=We will start from where we left off yesterday. Open {Code|src//Main.elm} in your editor. It should have the following code:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Element
+ import Svg
+ import Svg.Attributes
=
- main =
- Svg.svg
- [ Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- []
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ ]
+ []
= ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=It's a good starting point. We already have a single dot in the middle. Let's say this will be the center of our circle.
=
@@ -461,16 +497,20 @@ This will move the dot ("translate" is a fancy term for "move") 80 units.
=Also, let's change the color of the dot. In the end it should look like this:
=
=
-| Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
= ]
- []
- ]
=
=With this change, start the reactor by typing in your terminal:
=
@@ -493,78 +533,102 @@ As you can see the dot is no longer in the center - it has moved!
=
=Now we need a second dot. If you remember the discussion about lists from previous day, you know what to do. Just duplicate the first SVG circle and put it after the first one, with a coma in between. Like this:
=
-| Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "translate(80)"
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "translate(80)"
+ ]
+ []
= ]
- []
- ]
=
=Now let's focus on the second one. We gave it a different color, so we can distinguish between them, but now we don't see the first one! That's because it's exactly in the same spot as the second one, which covers it. They are stacked in a way. We need to move the second dot in a different direction, so it's on a circle, but 72 degree apart from the first one.
=
=For that we need to add another transformation before the move. First we will rotate, then translate:
=
-| Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
+| Editor
+ | Annotations
+ | Highlight
+ top = 14
+ left = 6
+ width = 53
+ height = 1
+
+ | Code
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
= ]
- []
- ]
=
=This will rotate the element by 72 degrees. On its own it wouldn't make any difference, because the dot is round - it doesn't matter how you rotate it, it always looks the same. But It also rotates it's internal coordinates system. So the translation will move it in a different direction then the first dot.
=
=Now it's time to add the third, red dot. Duplicate the second one, change fill to `"red"` and put `144` for rotate function, like this:
=
-| Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "red"
- , Svg.Attributes.transform "rotate(144) translate(80)"
+| Editor
+ | Annotations
+ | Highlight
+ top = 22
+ left = 6
+ width = 54
+ height = 1
+
+ | Fold
+ start = 1
+ length = 16
+
+ | Code
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
= ]
- []
- ]
=
=Why 144? It's because 72 + 72 is 144! So to be 72 degree apart from a dot that's at 72 degree, you need to be at 144 (or 0, but the first dot is already there).
=
@@ -573,64 +637,86 @@ This makes the last two dots trivial. Just rotate them to 216 and 288 and give t
=
=The complete program should look like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 41
+ left = 12
+ width = 54
+ height = 1
=
- import Element
- import Svg
- import Svg.Attributes
+ | Highlight
+ top = 49
+ left = 12
+ width = 54
+ height = 1
=
+ | Fold
+ start = 1
+ length = 35
=
- main =
- Svg.svg
- [ Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "red"
- , Svg.Attributes.transform "rotate(144) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "lime"
- , Svg.Attributes.transform "rotate(216) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "maroon"
- , Svg.Attributes.transform "rotate(288) translate(80)"
+ | Fold
+ start = 53
+ length = 7
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- []
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "lime"
+ , Svg.Attributes.transform "rotate(216) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "maroon"
+ , Svg.Attributes.transform "rotate(288) translate(80)"
+ ]
+ []
= ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=In the browser it should look exactly as we planned:
=index 155a00b..5e97ebd 100644
--- a/content/day-3.txt
+++ b/content/day-3.txt
@@ -255,64 +255,84 @@ If the name comes from an imported module, you need to prefix it with the name o
=
=Let's look at our code and try to recognize some literal values, lists, names and functions. Here is how it should look after day 2:
=
-| Code
- module Main exposing (main)
-
- import Element
- import Svg
- import Svg.Attributes
-
-
- main =
- Svg.svg
- [ Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
+| Editor
+ | Annotations
+ | Highlight
+ top = 3
+ left = 1
+ width = 21
+ height = 3
+
+ | Highlight
+ top = 10
+ left = 34
+ width = 19
+ height = 1
+
+ | Highlight
+ top = 8
+ left = 1
+ width = 6
+ height = 1
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "red"
- , Svg.Attributes.transform "rotate(144) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "lime"
- , Svg.Attributes.transform "rotate(216) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "maroon"
- , Svg.Attributes.transform "rotate(288) translate(80)"
- ]
- []
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "lime"
+ , Svg.Attributes.transform "rotate(216) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "maroon"
+ , Svg.Attributes.transform "rotate(288) translate(80)"
+ ]
+ []
= ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Take your time. Here are some hints to help you:
=
@@ -348,17 +368,162 @@ This block of code is repeated five times in our code - once for each dot. Now I
=
=First let's make them even more uniform by adding {Code|rotate(0)} to the first block. It will help us later. The code should look like this:
=
-| Code
- TODO
+| Editor
+ | Annotations
+ | Highlight
+ top = 16
+ left = 12
+ width = 52
+ height = 1
+
+ | Fold
+ start = 1
+ length = 7
=
+ | Fold
+ start = 20
+ length = 42
=
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "rotate(0) translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "lime"
+ , Svg.Attributes.transform "rotate(216) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "maroon"
+ , Svg.Attributes.transform "rotate(288) translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Then let's give the value produced by this block a name. We can call it the {Code|dot}. Select the first block that you have just modified, everything between {Code|[} and the {Code|,} on line 20 and cut it with {Key|command} + {Key|x}. Then in the empty space left type {Code|dot}.
=
=Move your cursor to the end of the file and type {Code|dot =}, press {Key|enter} and paste the code you cut before with {Key|command} + {Key|v}. The code should now look like this:
=
-| Code
- TODO
+| Editor
+ | Annotations
+ | Highlight
+ top = 12
+ left = 11
+ width = 3
+ height = 1
+
+ | Fold
+ start = 1
+ length = 7
+
+ | Fold
+ start = 21
+ length = 30
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "lime"
+ , Svg.Attributes.transform "rotate(216) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "maroon"
+ , Svg.Attributes.transform "rotate(288) translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ dot = Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "rotate(0) translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
=
=Reload the browser. Everything should work exactly the same as before. One of the dots is now a named value, but for our program it makes no difference. What is important is its value, not where it comes from.
=
@@ -374,74 +539,265 @@ Of course the goal is to have our list of dots looking like this:
=
=Let's try it. The effect will be that all the dots will be in the same place, one on top of another. Also they will all have the same color. So on the screen you should see only one dot, somewhat to the right of center.
=
-The dots need to have some parameters so they can be different. We already identified them: color and rotation. Above I said that a function is a parametrized value. Let's turn our dot definition on line {Code|TODO} into a function with two parameters like this:
+The dots need to have some parameters so they can be different. We already identified them: color and rotation. Above I said that a function is a parametrized value. Let's turn our dot definition on line {Code|52} into a function with two parameters like this:
=
-| Code
- TODO: Rest of the code
+| Editor
+ | Annotations
+ | None
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "skyblue"
- , Svg.Attributes.transform "rotate(0) translate(80)"
- ]
- []
+ | Fold
+ start = 1
+ length = 7
=
-This way we declared that when calling a {Code|dot} name you will provide two values: first one for {Code|color} and second for {Code|rotation}. Let's stay true to our word and provide it. Change the list on lines {Code|todo} to look like this:
+ | Fold
+ start = 13
+ length = 38
=
-| Code
- TODO: Rest of the code
+ | Code
+ module Main exposing (main)
=
- [ dot "skyblue" 0
- , dot "orange" 72
- , dot "red" 144
- , dot "lime" 216
- , dot "maroon" 288
- ]
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot color rotation
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "lime"
+ , Svg.Attributes.transform "rotate(216) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "maroon"
+ , Svg.Attributes.transform "rotate(288) translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ , Svg.Attributes.transform "rotate(0) translate(80)"
+ ]
+ []
+
+This way we declared that when calling a {Code|dot} name you will provide two values: first one for {Code|color} and second for {Code|rotation}. Let's stay true to our word and provide it. Change the list on lines {Code|12 - 16} to look like this:
+
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 1
+ length = 7
+
+ | Fold
+ start = 18
+ length = 5
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot "skyblue" 0
+ , dot "orange" 72
+ , dot "red" 144
+ , dot "lime" 216
+ , dot "maroon" 288
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ , Svg.Attributes.transform "rotate(0) translate(80)"
+ ]
+ []
=
=Let's reload again and see that there is still only one, skyblue dot visible. That's because we did not tell Elm what to do with the values of the two parameters we provide for the {Code|dot} function. We gave them names ({Code|color} and {Code|rotation}), but never called them.
=
-First, let's use the {Code|color} parameter. If you want to change the color of the dot, you need to pass a different value to the {Code|Svg.Attributes.fill} function on line {Code|TODO}. Currently the value is a literal string {Code|"skyblue"}. Instead we want to give it whatever value was given for the {Code|color} parameter. We do it by simply calling the name of the parameter in place of a literal value, like this:
+First, let's use the {Code|color} parameter. If you want to change the color of the dot, you need to pass a different value to the {Code|Svg.Attributes.fill} function on line {Code|12}. Currently the value is a literal string {Code|"skyblue"}. Instead we want to give it whatever value was given for the {Code|color} parameter. We do it by simply calling the name of the parameter in place of a literal value, like this:
=
+| Editor
+ | Annotations
+ | Highlight
+ top = 29
+ left = 31
+ width = 5
+ height = 1
=
-| Code
- TODO: Rest of the code
+ | Fold
+ start = 1
+ length = 7
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform "rotate(0) translate(80)"
- ]
- []
+ | Fold
+ start = 18
+ length = 5
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot "skyblue" 0
+ , dot "orange" 72
+ , dot "red" 144
+ , dot "lime" 216
+ , dot "maroon" 288
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform "rotate(0) translate(80)"
+ ]
+ []
=
=Now let's do the same for rotation. This one is more complex, because we cannot just pass {Code|rotation} value to the {Code|Svg.Attributes.transform} function. The {Code|rotation} is just a number, while the function expects a string formatted like this: {Code|"rotate(...) translate(80)"}.
=
=We can use the {Code|++} operator to glue the strings together. First part is constant, so we can just give it a literal value of {Code|"rotate("}. After that we put the {Code|++} and our variable part: {Code|rotation}. Finally the rest of the string is also constant: {Code|" translate(80)"} (notice the space before {Code|translate}!). All together we have:
=
-| Code
- TODO: Rest of the code
+| Editor
+ | Annotations
+ | None
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform "rotate(" ++ rotation ++ ") translate(80)"
- ]
- []
+ | Fold
+ start = 1
+ length = 23
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot "skyblue" 0
+ , dot "orange" 72
+ , dot "red" 144
+ , dot "lime" 216
+ , dot "maroon" 288
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform "rotate(" ++ rotation ++ ") translate(80)"
+ ]
+ []
=
=But Elm will complain about this. First it looks like we gave 5 arguments to the {Code|Svg.Attributes.transform} function, and it only takes one. We can fix it by putting a parentheses around the {Code|"rotate(" ++ rotation ++ ") translate(80)" }, basically telling Elm that this is a single expression and it should evaluate its value before passing it to the {Code|Svg.Attributes.transform} function. Now it should look like this:
=
-| Code
- TODO: Rest of the code
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 1
+ length = 23
+
+ | Code
+ module Main exposing (main)
=
- dot color rotation =
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ dot "skyblue" 0
+ , dot "orange" 72
+ , dot "red" 144
+ , dot "lime" 216
+ , dot "maroon" 288
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+ dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
= , Svg.Attributes.cx "0"
@@ -454,7 +810,26 @@ But Elm will complain about this. First it looks like we gave 5 arguments to the
=Here we face another problem. Elm complains with the following:
=
=| Monospace
- TODO: Provide error message. Make sure the line and column numbers are correct.
+ -- TYPE MISMATCH ------------------------------------------------ src/Main.elm
+
+ The 2nd argument to `dot` is not what I expect:
+
+ 12| [ dot "skyblue" 0
+ ^
+ This argument is a number of type:
+
+ number
+
+ But `dot` needs the 2nd argument to be:
+
+ String
+
+ Hint: I always figure out the argument types from left to right. If an argument
+ is acceptable, I assume it is "correct" and move on. So the problem may actually
+ be in one of the previous arguments!
+
+ Hint: Try using String.fromInt to convert it to a string?
+
=
=It's the type system in action. We can only use {Code|++} function with both arguments being the same type. Here one argument is:
=
@@ -480,36 +855,71 @@ Elm won't have that. Fortunately there is an easy way to satisfy the type system
=
=That's what we need! Let's pass the value of {Code|rotation} through this function like this:
=
-| Code
- TODO: Rest of the code
+| Editor
+ | Annotations
+ | None
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform ("rotate(" ++ (String.fromFloat rotation) ++ ") translate(80)")
- ]
- []
+ | Fold
+ start = 1
+ length = 23
=
-| Code
- IDEA: What if we use String.concat instead?
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- )
- ]
- []
+ [ dot "skyblue" 0
+ , dot "orange" 72
+ , dot "red" 144
+ , dot "lime" 216
+ , dot "maroon" 288
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform ("rotate(" ++ (String.fromFloat rotation) ++ ") translate(80)")
+ ]
+ []
+
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ IDEA: What if we use String.concat instead?
+
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ []
=
=This should work! The browser should now present the dots as intended and I hope you agree that the code is more readable now.
=
@@ -518,24 +928,28 @@ This should work! The browser should now present the dots as intended and I hope
=
=Armed with our functional superpowers, let's make another function that draws a line. Let me first show you a complete code and then we can discuss it.
=
-| Code
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=It works similar to the {Code|dot} function so you can just copy and paste it. Then apply the following changes:
=
@@ -554,70 +968,85 @@ It works similar to the {Code|dot} function so you can just copy and paste it. T
=
=Once you have the function defined, let's use it. For every dot, create one line, like so:
=
-| Code
- module Main exposing (main)
-
- import Element
- import Svg
- import Svg.Attributes
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 1
+ length = 7
+
+ | Fold
+ start = 20
+ length = 49
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ dot "skyblue" 0
+ , line "skyblue" 0
+ , dot "orange" 72
+ , line "orange" 72
+ , dot "red" 144
+ , line "red" 144
+ , dot "lime" 216
+ , line " lime" 216
+ , dot "maroon" 288
+ , line " maroon" 288
+ ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=
- main =
- [ dot "skyblue" 0
- , line "skyblue" 0
- , dot "orange" 72
- , line "orange" 72
- , dot "red" 144
- , dot "lime" 216
- , dot "maroon" 288
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
= ]
+ []
=
=
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=You should see something like this in the browser:
=index 03acab1..9d4ca1c 100644
--- a/content/day-4.txt
+++ b/content/day-4.txt
@@ -23,104 +23,128 @@
=
=The tree is built from segments: a line and a dot. In this respect it is similar to the connected dots we created yesterday. If we group the dot and a line, we will have the building block for our tree. We can do it with {Code|Svg.g} function ({Code|g} is an abbreviation of "group"). Just like {Code|Svg.svg}, it takes list of attributes and list of children. We can use it like that:
=
-| Code
- main =
- [ Svg.g []
- [ dot "skyblue" 0
- , line "skyblue" 0
- ]
- , Svg.g []
- [ dot "orange" 72
- , line "orange" 72
- ]
- , Svg.g []
- [ dot "red" 144
- , line "red" 144
- ]
- , Svg.g []
- [ dot "lime" 216
- , line "lime" 216
- ]
- , Svg.g []
- [ dot "maroon" 288
- , line "maroon" 288
- ]
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-100 -100 200 200"
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 23
+ length = 13
+
+ | Code
+ main =
+ [ Svg.g []
+ [ dot "skyblue" 0
+ , line "skyblue" 0
+ ]
+ , Svg.g []
+ [ dot "orange" 72
+ , line "orange" 72
= ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ , Svg.g []
+ [ dot "red" 144
+ , line "red" 144
= ]
+ , Svg.g []
+ [ dot "lime" 216
+ , line "lime" 216
+ ]
+ , Svg.g []
+ [ dot "maroon" 288
+ , line "maroon" 288
+ ]
+ ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Reload the browser there should be no difference at this point. Looking back at code I notice that each segment looks the same: it is a group with a dot and a line, where the {Code|group} and {Code|line} functions have the same arguments passed to them. This kind of repetition begs for a function. Let's call it {Code|segment} and define like this:
=
-| Code
- segment color rotation =
- Svg.g []
- [ dot color rotation
- , line color rotation
- ]
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ segment color rotation =
+ Svg.g []
+ [ dot color rotation
+ , line color rotation
+ ]
=
=Type this code at the bottom of the file and then replace main with the following:
=
-| Code
- main =
- [ segment "skyblue" 0
- , segment "orange" 72
- , segment "red" 144
- , segment "lime" 216
- , segment "maroon" 288
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-100 -100 200 200"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 8
+ length = 13
+
+ | Code
+ main =
+ [ segment "skyblue" 0
+ , segment "orange" 72
+ , segment "red" 144
+ , segment "lime" 216
+ , segment "maroon" 288
+ ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=| Note
= I hope you can see the pattern in what we are doing. We are taking repetitive blocks of code and turning them into named functions. Parameters help us deal with variability in the repeated code (like color and rotation that is different for each segment).
=
=Reload the browser. There should still be no visible difference in the behavior of the program, but our source code is getting more readable. That's good.
=
-The big difference between our program and the one we are trying to build is that our have only one level of segments, whereas in the example segments grow from the tip of other segments. You can think of it as segments having child segments: the green segment has two child brown segments. Each brown segment has three red child segments
+The big difference between our program and the one we are trying to build is that ours have only one level of segments, whereas in the example segments grow from the tip of other segments. You can think of it as segments having child segments: the green segment has two child brown segments. Each brown segment has three red child segments
=
=| Note
= TODO: Make sure the description matches the example
=
-It's similar to how the way an SVG group has child elements. But group itself (together with it's children) is an element, so we can put a group within a group. Let's do that! Change the definition of {Code|segment} function as follows:
+It's similar to how the way an SVG group has child elements. But group itself (together with its children) is an element, so we can put a group within a group. Let's do that! Change the definition of {Code|segment} function as follows:
=
-| Code
- segment color rotation =
- Svg.g []
- [ dot color rotation
- , line color rotation
- , Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- [ dot "red" 15
- , line "red" 15
- , dot "blue" -15
- , line "blue" -15
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ segment color rotation =
+ Svg.g []
+ [ dot color rotation
+ , line color rotation
+ , Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ [ dot "red" 15
+ , line "red" 15
+ , dot "blue" -15
+ , line "blue" -15
+ ]
= ]
- ]
=
=Now the program should display something like this:
=
@@ -131,26 +155,30 @@ It's already starts to look interesting, but there are two problems with it. Fir
=
=Then the lines look ugly displayed on top of the dots of different color. This is also easy to fix. In SVG several siblings (children of the same parent element) lay one on top of another. The "younger" sibling is laying on top of the older, so in our case the group containing the blue and red dots and lines lays on top of the dot and line. Let's change the order of siblings by moving the group to the beginning of the list, like this:
=
-| Code
- segment color rotation =
- Svg.g []
- [ Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- [ dot "red" 15
- , line "red" 15
- , dot "blue" -15
- , line "blue" -15
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ segment color rotation =
+ Svg.g []
+ [ Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ [ dot "red" 15
+ , line "red" 15
+ , dot "blue" -15
+ , line "blue" -15
+ ]
+ , dot color rotation
+ , line color rotation
= ]
- , dot color rotation
- , line color rotation
- ]
=
=With this two changes applied you should see something like this in the browser:
=
@@ -159,45 +187,77 @@ With this two changes applied you should see something like this in the browser:
=
=So now each segment has two sub segments: red and blue. The red one is rotate 15 degree clockwise, the blue one is rotated 15 degree counterclockwise. But they are look the same. Our goal is to make them variable. This means that we need one more parameter to the segment: list of children. Let's do it:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
+ | Fold
+ start = 1
+ length = 7
=
+ | Fold
+ start = 21
+ length = 12
=
- main =
- [ segment "skyblue"
- 0
- [ dot "red" 15
- , line "red" 15
- , dot "blue" -15
- , line "blue" -15
- ]
- , segment "orange" 72 []
- , segment "red" 144 []
- , segment "lime" 216 []
- , segment "maroon" 288 []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
+
+
+ main =
+ [ segment "skyblue"
+ 0
+ [ dot "red" 15
+ , line "red" 15
+ , dot "blue" -15
+ , line "blue" -15
= ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ , segment "orange" 72 []
+ , segment "red" 144 []
+ , segment "lime" 216 []
+ , segment "maroon" 288 []
+ ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ segment : String -> Float -> List (Svg msg) -> Svg.Svg msg
+ segment color rotation children =
+ Svg.g []
+ [ Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ children
+ , dot color rotation
+ , line color rotation
= ]
=
=
- segment : String -> Float -> List (Svg msg) -> Svg.Svg msg
- segment color rotation children =
- Svg.g []
- [ Svg.g
- [ Svg.Attributes.transform
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
= (String.concat
= [ "rotate("
= , String.fromFloat rotation
@@ -205,46 +265,26 @@ So now each segment has two sub segments: red and blue. The red one is rotate 15
= ]
= )
= ]
- children
- , dot color rotation
- , line color rotation
- ]
-
-
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ []
+
+
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=
=We have added third parameter to {Code|segment} function on line 34 (before the changes it was 28). The parameter is named {Code|children} and we use it in place of the list on line 45 (previously 39). The list itself was moved to line 11, where it is passed as a value for the parameter of the first segment. This move made all the lines shift down. All other segments will also need to get value for {Code|children} parameter, so let's just give each of them an empty list - meaning they have 0 children.
@@ -256,63 +296,107 @@ Once all changes are applied, reload the browser and see that only first, skyblu
=
=Before we continue, let's notice that on lines 11 - 15 we have a nice opportunity to remove some repetition. Consider that dot and a line with same rotation and color are just a segment. We can replace:
=
-| Code
- [ dot "red" 15
- , line "red" 15
- , dot "blue" -15
- , line "blue" -15
- ]
+| Editor
+ | Annotations
+ | None
=
-with:
-
-| Code
- [ segment "red" 15 []
- , segment "blue" -15 []
- ]
+ | Code
+ [ dot "red" 15
+ , line "red" 15
+ , dot "blue" -15
+ , line "blue" -15
+ ]
=
-A segment within a segment! Consider that every segment can have child segments. This way we can build a tree as complex as we want. Try adding more children:
+with:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
+ | Code
+ [ segment "red" 15 []
+ , segment "blue" -15 []
+ ]
=
+A segment within a segment! Consider that every segment can have child segments. This way we can build a tree as complex as we want. Try adding more children:
=
- main =
- [ segment "skyblue"
- 0
- [ segment "red" 15 []
- , segment "blue"
- -15
- [ segment "yellow" 45 []
- , segment "pink" -20 []
- , segment "green" -90 []
+| Editor
+ | Annotations
+ | Highlight
+ top = 28
+ left = 12
+ width = 50
+ height = 1
+
+ | Fold
+ start = 1
+ length = 7
+
+ | Fold
+ start = 30
+ length = 60
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
+
+
+ main =
+ [ segment "skyblue"
+ 0
+ [ segment "red" 15 []
+ , segment "blue"
+ -15
+ [ segment "yellow" 45 []
+ , segment "pink" -20 []
+ , segment "green" -90 []
+ ]
= ]
+ , segment "orange" 72 []
+ , segment "red" 144 []
+ , segment "lime" 216 []
+ , segment "maroon" 288 []
= ]
- , segment "orange" 72 []
- , segment "red" 144 []
- , segment "lime" 216 []
- , segment "maroon" 288 []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ segment color rotation children =
+ Svg.g []
+ [ Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ children
+ , dot color rotation
+ , line color rotation
= ]
=
=
- segment color rotation children =
- Svg.g []
- [ Svg.g
- [ Svg.Attributes.transform
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
= (String.concat
= [ "rotate("
= , String.fromFloat rotation
@@ -320,46 +404,26 @@ A segment within a segment! Consider that every segment can have child segments.
= ]
= )
= ]
- children
- , dot color rotation
- , line color rotation
- ]
-
-
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ []
+
+
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=| Emphasize
= Time to play 🌳🌲🌴🎄
@@ -401,45 +465,77 @@ To represent this in code we will need to learn few new concepts: *dictionary*,
=
=Let's start with a record. Currently our {Code|segment} function takes three arguments first two are {Code|color : String} and {Code|rotation : Float}. The last one is a list of child segments. Instead we can merge the first two into one argument of type {Code|\{ color : String, rotation : Float \\}}. It will look like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 1
+ length = 7
+
+ | Fold
+ start = 22
+ length = 66
=
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
+ | Code
+ module Main exposing (main)
=
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
=
- main =
- [ segment { color = "skyblue", rotation = 0 }
- [ segment { color = "red", rotation = 15 } []
- , segment { color = "blue", rotation = -15 }
- [ segment { color = "yellow", rotation = 45 } []
- , segment { color = "pink", rotation = -20 } []
- , segment { color = "green", rotation = -90 } []
+
+ main =
+ [ segment { color = "skyblue", rotation = 0 }
+ [ segment { color = "red", rotation = 15 } []
+ , segment { color = "blue", rotation = -15 }
+ [ segment { color = "yellow", rotation = 45 } []
+ , segment { color = "pink", rotation = -20 } []
+ , segment { color = "green", rotation = -90 } []
+ ]
= ]
+ , segment { color = "orange", rotation = 72 } []
+ , segment { color = "red", rotation = 144 } []
+ , segment { color = "lime", rotation = 216 } []
+ , segment { color = "maroon", rotation = 288 } []
= ]
- , segment { color = "orange", rotation = 72 } []
- , segment { color = "red", rotation = 144 } []
- , segment { color = "lime", rotation = 216 } []
- , segment { color = "maroon", rotation = 288 } []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+ segment { color, rotation } children =
+ Svg.g []
+ [ Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ children
+ , dot color rotation
+ , line color rotation
= ]
=
=
- segment { color, rotation } children =
- Svg.g []
- [ Svg.g
- [ Svg.Attributes.transform
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
= (String.concat
= [ "rotate("
= , String.fromFloat rotation
@@ -447,46 +543,26 @@ Let's start with a record. Currently our {Code|segment} function takes three arg
= ]
= )
= ]
- children
- , dot color rotation
- , line color rotation
- ]
-
-
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ []
+
+
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=Not much changed. Instead of passing two separate values for {Code|color} and {Code|rotation} we pass one value with two named fields. That's a record!
=
@@ -494,60 +570,97 @@ Why did I do it? That way I can store complete information about a segment in on
=
=Dictionary let's us associate one value (let's say color) with another value (let's say a list of segments). You can have as many entries in your dictionary as you want. That's perfect for storing our rules. We can start with an empty dictionary and then add our two rules: one for brown and one for green segments. We do it like this:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | Highlight
+ top = 3
+ left = 1
+ width = 11
+ height = 1
+
+ | Fold
+ start = 8
+ length = 27
+
+ | Fold
+ start = 48
+ length = 55
=
- import Dict
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
=
+ | Code
+ module Main exposing (main)
=
- main =
- [ segment { color = "skyblue", rotation = 0 }
- [ segment { color = "red", rotation = 15 } []
- , segment { color = "blue", rotation = -15 }
- [ segment { color = "yellow", rotation = 45 } []
- , segment { color = "pink", rotation = -20 } []
- , segment { color = "green", rotation = -90 } []
+ import Dict
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
+
+
+ main =
+ [ segment { color = "skyblue", rotation = 0 }
+ [ segment { color = "red", rotation = 15 } []
+ , segment { color = "blue", rotation = -15 }
+ [ segment { color = "yellow", rotation = 45 } []
+ , segment { color = "pink", rotation = -20 } []
+ , segment { color = "green", rotation = -90 } []
+ ]
= ]
+ , segment { color = "orange", rotation = 72 } []
+ , segment { color = "red", rotation = 144 } []
+ , segment { color = "lime", rotation = 216 } []
+ , segment { color = "maroon", rotation = 288 } []
= ]
- , segment { color = "orange", rotation = 72 } []
- , segment { color = "red", rotation = 144 } []
- , segment { color = "lime", rotation = 216 } []
- , segment { color = "maroon", rotation = 288 } []
- ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=
- rules =
- Dict.empty
- |> Dict.insert "brown"
- [ { color = "green", rotation = 0 }
- , { color = "green", rotation = 20 }
- , { color = "green", rotation = -30 }
- ]
- |> Dict.insert "green"
- [ { color = "red", rotation = -45 }
- , { color = "red", rotation = -5 }
- , { color = "red", rotation = 50 }
+ rules =
+ Dict.empty
+ |> Dict.insert "brown"
+ [ { color = "green", rotation = 0 }
+ , { color = "green", rotation = 20 }
+ , { color = "green", rotation = -30 }
+ ]
+ |> Dict.insert "green"
+ [ { color = "red", rotation = -45 }
+ , { color = "red", rotation = -5 }
+ , { color = "red", rotation = 50 }
+ ]
+
+
+ segment { color, rotation } children =
+ Svg.g []
+ [ Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ children
+ , dot color rotation
+ , line color rotation
= ]
=
=
- segment { color, rotation } children =
- Svg.g []
- [ Svg.g
- [ Svg.Attributes.transform
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
= (String.concat
= [ "rotate("
= , String.fromFloat rotation
@@ -555,46 +668,26 @@ Dictionary let's us associate one value (let's say color) with another value (le
= ]
= )
= ]
- children
- , dot color rotation
- , line color rotation
- ]
-
-
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ []
+
+
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=We have added an import statement for {Code|Dict} module and created a dictionary with two entries: one for {Code|"brown"} and one for {Code|"green"}. The values associated with these keys are a list of segment records. The meaning of this is following:
=
@@ -606,43 +699,51 @@ There is no rule for red segments, so they will have no children. Now we will ap
=
=Here it is:
=
-| Code
- segment { color, rotation } =
- Svg.g []
- [ rules
- |> Dict.get color
- |> Maybe.withDefault []
- |> List.map segment
- |> Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- , dot color rotation
- , line color rotation
- ]
-
-We also have to change the definition of {Code|main}. Segment no longer takes two arguments, and it's children are calculated according to rules, so we can just add one brown segment and rotate it upward (-90 degree)
+| Editor
+ | Annotations
+ | None
=
-| Code
- main =
- [ segment { color = "brown", rotation = -90 } ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
+ | Code
+ segment { color, rotation } =
+ Svg.g []
+ [ rules
+ |> Dict.get color
+ |> Maybe.withDefault []
+ |> List.map segment
+ |> Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ , dot color rotation
+ , line color rotation
= ]
=
+We also have to change the definition of {Code|main}. Segment no longer takes two arguments, and its children are calculated according to rules, so we can just add one brown segment and rotate it upward (-90 degree)
+
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ main =
+ [ segment { color = "brown", rotation = -90 } ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
=The result should be exactly like we wanted it to be:
=
=| Monospace
@@ -689,25 +790,29 @@ The result should be exactly like we wanted it to be:
=
=Nice, but what's going on here:
=
-| Code
- segment { color, rotation } =
- Svg.g []
- [ rules
- |> Dict.get color
- |> Maybe.withDefault []
- |> List.map segment
- |> Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- , dot color rotation
- , line color rotation
- ]
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ segment { color, rotation } =
+ Svg.g []
+ [ rules
+ |> Dict.get color
+ |> Maybe.withDefault []
+ |> List.map segment
+ |> Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ , dot color rotation
+ , line color rotation
+ ]
=
=There are three new things here:
=
@@ -781,102 +886,118 @@ So that won't work. But it would be nice to have arbitrarily complex trees with
=
=We can do it like this. When we create our first segment (the brown one), we will pass it a second argument (let's call it {Code|age}). It will be an integer. The age of a parent will be decremented and passed to all it's children (so every child is younger than it's parent by one generation). Eventually the program will reach segments with {Code|age} being {Code|0}. This segment will have no children, thus stopping the whole process. Here is how we can implement it:
=
-| Code
- module Main exposing (main)
-
- import Dict
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
-
+| Editor
+ | Annotations
+ | Highlight
+ top = 10
+ left = 4
+ width = 49
+ height = 1
+
+ | Fold
+ start = 1
+ length = 8
+
+ | Fold
+ start = 62
+ length = 36
+
+ | Code
+ module Main exposing (main)
+
+ import Dict
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
+
+
+ main =
+ [ segment 4 { color = "brown", rotation = -90 } ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
- main =
- [ segment 4 { color = "brown", rotation = -90 } ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
=
+ rules =
+ Dict.empty
+ |> Dict.insert "brown"
+ [ { color = "brown", rotation = 0 }
+ , { color = "green", rotation = 20 }
+ , { color = "green", rotation = -30 }
+ ]
+ |> Dict.insert "green"
+ [ { color = "red", rotation = -45 }
+ , { color = "red", rotation = -5 }
+ , { color = "red", rotation = 50 }
+ ]
=
- rules =
- Dict.empty
- |> Dict.insert "brown"
- [ { color = "brown", rotation = 0 }
- , { color = "green", rotation = 20 }
- , { color = "green", rotation = -30 }
- ]
- |> Dict.insert "green"
- [ { color = "red", rotation = -45 }
- , { color = "red", rotation = -5 }
- , { color = "red", rotation = 50 }
- ]
=
+ segment age { color, rotation } =
+ if age <= 0 then
+ Svg.g [] []
+
+ else
+ Svg.g []
+ [ rules
+ |> Dict.get color
+ |> Maybe.withDefault []
+ |> List.map (segment (age - 1))
+ |> Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ , dot color rotation
+ , line color rotation
+ ]
=
- segment age { color, rotation } =
- if age <= 0 then
- Svg.g [] []
=
- else
- Svg.g []
- [ rules
- |> Dict.get color
- |> Maybe.withDefault []
- |> List.map (segment (age - 1))
- |> Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
+ dot color rotation =
+ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
= ]
- , dot color rotation
- , line color rotation
+ )
= ]
-
-
- dot color rotation =
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
-
-
- line color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 "80"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
- ]
- )
- ]
- []
+ []
+
+
+ line color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 "80"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=On line 10 we pass the age to the {Code|segment} function as the first argument. The record is a second parameter now. The reason is that it makes mapping on line 47 easier. Age is the same for all the children (age of the parent minus 1).
=
@@ -948,46 +1069,50 @@ I hope you had fun playing with the tree. You can make it really interesting and
=
=Since the size depends on the age, and the age is given for every segment, we can fix that relatively easy. Let's start by making the dots smaller or bigger depending on the age of the segment, like this:
=
-| Code
- segment age { color, rotation } =
- if age <= 0 then
- Svg.g [] []
+| Editor
+ | Annotations
+ | None
+
+ | Code
+ segment age { color, rotation } =
+ if age <= 0 then
+ Svg.g [] []
+
+ else
+ Svg.g []
+ [ rules
+ |> Dict.get color
+ |> Maybe.withDefault []
+ |> List.map (segment (age - 1))
+ |> Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
+ ]
+ )
+ ]
+ , dot age color rotation
+ , line color rotation
+ ]
=
- else
- Svg.g []
- [ rules
- |> Dict.get color
- |> Maybe.withDefault []
- |> List.map (segment (age - 1))
- |> Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
+
+ dot age color rotation =
+ Svg.circle
+ [ Svg.Attributes.r (String.fromFloat age)
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate(80)"
= ]
- , dot age color rotation
- , line color rotation
+ )
= ]
-
-
- dot age color rotation =
- Svg.circle
- [ Svg.Attributes.r (String.fromFloat age)
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate(80)"
- ]
- )
- ]
- []
+ []
=
=| Monospace
= TODO: Describe the change to code
@@ -996,107 +1121,115 @@ Next let's pass the age to the {Code|line} function and use it for both the thic
=
=If you reload now, the tree will look as if it exploded. It's funny. The reason is that we did not adjust the translation of the child groups nor the dots. It's always 80, even though the length of the lines is variable - see lines {Code|TODO: line of group translation} and {Code|TODO: line of dot translation}. Let's change it like that:
=
-| Code
- module Main exposing (main)
+| Editor
+ | Annotations
+ | None
=
- import Dict
- import Element
- import Svg exposing (Svg)
- import Svg.Attributes
+ | Fold
+ start = 1
+ length = 37
=
+ | Code
+ module Main exposing (main)
=
- main =
- [ segment 4 { color = "brown", rotation = -90 } ]
- |> Svg.svg
- [ Svg.Attributes.height "100%"
- , Svg.Attributes.width "100%"
- , Svg.Attributes.style "background: none"
- , Svg.Attributes.viewBox "-500 -500 1000 1000"
- ]
- |> Element.html
- |> Element.layout
- [ Element.width Element.fill
- , Element.height Element.fill
- ]
+ import Dict
+ import Element
+ import Svg exposing (Svg)
+ import Svg.Attributes
=
=
- rules =
- Dict.empty
- |> Dict.insert "brown"
- [ { color = "brown", rotation = 0 }
- , { color = "green", rotation = 20 }
- , { color = "green", rotation = -30 }
- ]
- |> Dict.insert "green"
- [ { color = "red", rotation = -45 }
- , { color = "red", rotation = -5 }
- , { color = "red", rotation = 50 }
- ]
-
+ main =
+ [ segment 4 { color = "brown", rotation = -90 } ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.style "background: none"
+ , Svg.Attributes.viewBox "-500 -500 1000 1000"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
- segment age { color, rotation } =
- if age <= 0 then
- Svg.g [] []
=
- else
- Svg.g []
- [ rules
- |> Dict.get color
- |> Maybe.withDefault []
- |> List.map (segment (age - 1))
- |> Svg.g
- [ Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate("
- , String.fromFloat (age * 10)
- , ")"
- ]
- )
- ]
- , dot age color rotation
- , line age color rotation
- ]
+ rules =
+ Dict.empty
+ |> Dict.insert "brown"
+ [ { color = "brown", rotation = 0 }
+ , { color = "green", rotation = 20 }
+ , { color = "green", rotation = -30 }
+ ]
+ |> Dict.insert "green"
+ [ { color = "red", rotation = -45 }
+ , { color = "red", rotation = -5 }
+ , { color = "red", rotation = 50 }
+ ]
=
=
- dot age color rotation =
- Svg.circle
- [ Svg.Attributes.r (String.fromFloat age)
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill color
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ") translate("
- , String.fromFloat (age * 10)
- , ")"
- ]
- )
- ]
- []
-
-
- line age color rotation =
- Svg.line
- [ Svg.Attributes.strokeWidth "1"
- , Svg.Attributes.x1 "0"
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.x1 (String.fromFloat (age * 10))
- , Svg.Attributes.y1 "0"
- , Svg.Attributes.stroke color
- , Svg.Attributes.strokeWidth (String.fromFloat age)
- , Svg.Attributes.transform
- (String.concat
- [ "rotate("
- , String.fromFloat rotation
- , ")"
+ segment age { color, rotation } =
+ if age <= 0 then
+ Svg.g [] []
+
+ else
+ Svg.g []
+ [ rules
+ |> Dict.get color
+ |> Maybe.withDefault []
+ |> List.map (segment (age - 1))
+ |> Svg.g
+ [ Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate("
+ , String.fromFloat (age * 10)
+ , ")"
+ ]
+ )
+ ]
+ , dot age color rotation
+ , line age color rotation
= ]
- )
- ]
- []
+
+
+ dot age color rotation =
+ Svg.circle
+ [ Svg.Attributes.r (String.fromFloat age)
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill color
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ") translate("
+ , String.fromFloat (age * 10)
+ , ")"
+ ]
+ )
+ ]
+ []
+
+
+ line age color rotation =
+ Svg.line
+ [ Svg.Attributes.strokeWidth "1"
+ , Svg.Attributes.x1 "0"
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.x1 (String.fromFloat (age * 10))
+ , Svg.Attributes.y1 "0"
+ , Svg.Attributes.stroke color
+ , Svg.Attributes.strokeWidth (String.fromFloat age)
+ , Svg.Attributes.transform
+ (String.concat
+ [ "rotate("
+ , String.fromFloat rotation
+ , ")"
+ ]
+ )
+ ]
+ []
=
=Now the tree should look correctly, like this:
=index c073ebc..fe7dc56 100644
--- a/content/day-5.txt
+++ b/content/day-5.txt
@@ -93,6 +93,23 @@ State is sometimes called model. There are also commands, but we will not use th
=First let's change the value of {Code|main} and create the {Code|view} function, like this:
=
=| Editor
+ | Annotations
+ | Highlight
+ top = 10
+ left = 4
+ width = 35
+ height = 6
+
+ | Highlight
+ top = 18
+ left = 1
+ width = 8
+ height = 1
+
+ | Fold
+ start = 31
+ length = 81
+
= | Code
= module Main exposing (main)
=
@@ -102,7 +119,6 @@ First let's change the value of {Code|main} and create the {Code|view} function,
= import Svg exposing (Svg)
= import Svg.Attributes
=
-
= main =
= Browser.element
= { init = init
@@ -205,24 +221,6 @@ First let's change the value of {Code|main} and create the {Code|view} function,
= ]
= []
=
- | Highlight
- from = 11
- to = 16
- offset = 4
- width = 35
-
- | Highlight
- from = 19
- to = 19
- offset = 0
- width = 10
-
- | Highlight
- from = 20
- to = 20
- offset = 15
- width = 10
-
=Notice that the {Code|view} takes an argument called {Code|age} and passes it to the first (brown) segment. The value of {Code|age} is our state. In some programs the type of state can be very complex, but in our program it's simply a {Code|Float} number. It will indicate how much time in milliseconds have passed from the start of the program. Because the time is counted in milliseconds, to get correct results we need to divide it by 5000 (so the tree will grows one generation of segments per five second).
=
=Now let's provide the init function. It takes an argument sometimes called flags, but we will ignore it. Let's just say that it will always receive {Code|()} - an empty value called unit. It needs to return two values bound together in a structure called /tuple/.
@@ -237,16 +235,13 @@ First value is more important. This is the initial age of the tree, right after
=That's our init:
=
=| Editor
+ | Annotations
+ | None
+
= | Code
= init () =
= ( 0, Cmd.none )
=
- | Highlight
- from = 0
- to = 0
- offset = 0
- width = 10
-
=Time for the {Code|update} function. It will get two arguments: an incoming message and the current state. Incoming message will always be a duration of time since previous frame, so let's simply call it {Code|duration}. The state is the current age of the tree, so again we can call it {Code|age}. In return we must produce a tuple with:
=
=| List
@@ -256,18 +251,15 @@ Time for the {Code|update} function. It will get two arguments: an incoming mess
=It looks like this:
=
=| Editor
+ | Annotations
+ | None
+
= | Code
= update duration age =
= ( age + duration
= , Cmd.none
= )
=
- | Highlight
- from = 0
- to = 0
- offset = 0
- width = 10
-
=Finally let's subscribe to the events marking the passage of time. We can do it using {Code|Browser.Events.onAnimationFrameDelta}. Here is how it works. Whenever the browser is ready for the next frame it will send us a message containing the number of milliseconds that have passed since previous frame.
=
=To use it we first need to import the {Code|Browser.Events} module. The {Code|Browser.Events.onAnimationFrameDelta} function expects us to give it a function that will get a duration and return a message. But our message is simply a duration! We don't need to do anything with it, just take it as it is. So we need a function that just returns whatever it gets. This function is called {Code|identity}.
@@ -278,19 +270,43 @@ To use it we first need to import the {Code|Browser.Events} module. The {Code|Br
=The whole {Code|subscriptions} looks like that:
=
=| Editor
+ | Annotations
+ | None
+
= | Code
= subscriptions age =
= Browser.Events.onAnimationFrameDelta identity
=
- | Highlight
- from = 0
- to = 0
- offset = 0
- width = 10
-
=And the complete code like this:
=
=| Editor
+ | Annotations
+ | Highlight
+ top = 20
+ left = 1
+ width = 19
+ height = 2
+
+ | Highlight
+ top = 39
+ left = 1
+ width = 31
+ height = 7
+
+ | Fold
+ start = 1
+ length = 18
+
+ | Highlight
+ top = 48
+ left = 1
+ width = 49
+ height = 2
+ | Fold
+ start = 51
+ length = 81
+
+
= | Code
= module Main exposing (main)
=
@@ -421,12 +437,6 @@ And the complete code like this:
= ]
= []
=
- | Highlight
- from = 0
- to = 0
- offset = 0
- width = 10
-
=
=| Emphasize
= That's it!Fix fold taking one line too many.
index 07cf136..16a919a 100644
--- a/src/Mark/Custom.elm
+++ b/src/Mark/Custom.elm
@@ -137,7 +137,7 @@ editor =
= extractAnnotations
= { extracted
= | folded =
- (start + length)
+ (start + length - 1)
= |> List.range start
= |> Set.fromList
= |> Set.union foldedProvide contact information in index document.
Improve Emphasize block to allow multiple text blocks. All of them are centered but only the first one is big.
Co-Authored-By: Tadeusz Łazurski tadeusz@lazurski.pl
index 2547076..84b1c24 100644
--- a/content/index.txt
+++ b/content/index.txt
@@ -4,11 +4,15 @@
=| Emphasize
= ⚘
=
-| Emphasize
= A software development workshop for non-programmers
=
=Hello! We are running a workshop that will give you a glimpse into the way software is created. Our workshop is intended for people with no prior experience in programming and doesn't require any technical knowledge. Everybody is welcome!
=
+| Emphasize
+ Say hello {Icon|name=phone} {Link|+31 638 216 166|url=tel:+31638216166}
+
+ or drop us a note at {Link|fana@software.garden|url= mailto:fana@software.garden}
+
=Below is material through which we will be going during the workshop. Only the first section is a required read before you come, but feel free to read more to get more prepared.
=
=| Listindex ddbec4e..1a9f28e 100644
--- a/src/Mark/Custom.elm
+++ b/src/Mark/Custom.elm
@@ -315,22 +315,41 @@ note =
=emphasize : Mark.Block (model -> Element msg)
=emphasize =
= let
- render elements model =
- model
- |> elements
- |> Element.paragraph []
- |> Element.el
- [ Element.spacing 30
- , Font.bold
- , Font.size 30
- , Font.center
+ render texts model =
+ let
+ elements =
+ texts
+ |> List.map (\fn -> fn model)
+
+ heading =
+ List.head elements
+ |> Maybe.withDefault [ Element.none ]
+ |> Element.paragraph
+ [ Element.width Element.fill
+ , Font.bold
+ , Font.size 30
+ ]
+
+ subheadings =
+ elements
+ |> List.drop 1
+ |> List.map
+ (Element.paragraph
+ [ Element.width Element.fill
+ ]
+ )
+ in
+ (heading :: subheadings)
+ |> Element.textColumn
+ [ Font.center
= , Element.paddingXY 0 40
= , Element.width Element.fill
+ , Element.spacing 10
= ]
= in
= Mark.block "Emphasize"
= render
- text
+ (Mark.manyOf [ text ])
=
=
=image : Mark.Block (model -> Element msg)Merge remote-tracking branch 'origin/contact' into content
Make the width and padding of the main column respond to device class
On mobile devices in portrait orientation fill the screen with a fixed padding. Otherwise try to set width to maximum of 960 (but see https://github.com/mdgriffith/elm-ui/issues/42).
index bf183c7..d01b51a 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -619,11 +619,36 @@ document =
= children
= |> List.map (\child -> child model.examples)
= |> Element.textColumn
- [ Element.centerX
- , Element.spacing 20
+ (model.viewport
+ |> Element.classifyDevice
+ |> responsiveAttributes
+ |> (++)
+ [ Element.centerX
+ , Element.spacing 20
+ ]
+ )
+ |> View title
+
+ responsiveAttributes { class, orientation } =
+ case ( class, orientation ) of
+ ( Element.Phone, Element.Portrait ) ->
+ [ Element.width Element.fill
+ , Element.paddingXY 10 80
+ ]
+
+ ( Element.Tablet, Element.Portrait ) ->
+ [ Element.width Element.fill
+ , Element.paddingXY 20 80
+ ]
+
+ _ ->
+ [ Element.width
+ (Element.fill
+ |> Element.maximum 960
+ |> Element.minimum 500
+ )
= , Element.paddingXY 0 80
= ]
- |> View title
=
= {- The document has to start with a Title block containing a String (i.e. single line of unforamtted text). This String will be used in two ways:
=Add subtle material-style shadow to navigation bar
index d01b51a..4739a1a 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -491,15 +491,26 @@ homeNavigationBar =
=contentNavigationBar : Model -> Element Msg
=contentNavigationBar { location, scroll, viewport } =
= let
- links : List { url : String, label : String, icon : Element msg }
+ links :
+ List
+ { url : String
+ , label : String
+ , icon : Element msg
+ }
= links =
= [ { url = "/"
= , label = "Home"
- , icon = FeatherIcons.home |> FeatherIcons.toHtml [] |> Element.html
+ , icon =
+ FeatherIcons.home
+ |> FeatherIcons.toHtml []
+ |> Element.html
= }
= , { url = "/preparation.html"
= , label = "Get ready"
- , icon = FeatherIcons.bookOpen |> FeatherIcons.toHtml [] |> Element.html
+ , icon =
+ FeatherIcons.bookOpen
+ |> FeatherIcons.toHtml []
+ |> Element.html
= }
= , { url = "/day-1.html"
= , label = "Day 1"
@@ -523,11 +534,21 @@ contentNavigationBar { location, scroll, viewport } =
= }
= ]
=
- linkElement : { url : String, label : String, icon : Element Msg } -> Element Msg
+ linkElement :
+ { url : String
+ , label : String
+ , icon : Element Msg
+ }
+ -> Element Msg
= linkElement link =
= Element.link
= [ Element.width Element.fill
- , Element.paddingEach { top = 40, right = 5, bottom = 20, left = 5 }
+ , Element.paddingEach
+ { top = 40
+ , right = 5
+ , bottom = 20
+ , left = 5
+ }
= ]
= { url = link.url
= , label =
@@ -594,6 +615,17 @@ contentNavigationBar { location, scroll, viewport } =
= Element.column
= [ Element.width Element.fill
= , Background.color (Element.rgb 1 1 1)
+ , Border.shadow
+ { offset = ( 0, 0 )
+ , size = 1
+ , blur = 3
+ , color =
+ if scroll == 0 then
+ Element.rgba 0.8 0.8 0.8 0
+
+ else
+ Element.rgb 0.8 0.8 0.8
+ }
= , Element.htmlAttribute (Html.Attributes.id "navigation-bar")
= ]
= [ linksRow