Commits: 5
Fix typo
index 32fc805..e54b4b9 100644
--- a/content/day-5.txt
+++ b/content/day-5.txt
@@ -6,7 +6,7 @@
=
=
=| Note
- Today we are going to lear about
+ Today we are going to learn about
=
= | List
= - The Elm ArchitectureControl oprhans in paragraphs
See https://css-tricks.com/almanac/properties/o/orphans/
index b49f7d3..8430329 100644
--- a/src/Mark/Custom.elm
+++ b/src/Mark/Custom.elm
@@ -55,6 +55,7 @@ paragraph =
= [ Element.paddingXY 0 10
= , Element.spacing 12
= , css "hyphens" "auto"
+ , css "orphans" "3"
= , Font.justify
= ]
= (content model)Write first section of day 4 - manual tree
index ea07e93..80d31eb 100644
--- a/content/day-4.txt
+++ b/content/day-4.txt
@@ -1,20 +1,372 @@
=| Title
- Day 3
+ Day 4
=
=| Emphasize
= Let's Make a Tree
=
+| Note
+ *We are still working on this content.*
+
+ Stay tuned {Icon|name=radio}
=
=| Note
- Today we are going to lear about
+ Last day we have learned about basic building blocks of an Elm program: *value*, *name* and *type*. Today we are going to use this blocks to compose more complex structures. On the way we are going to learn about:
=
= | List
- - Recursion
+ -> Recursion
=
=| Header
= The Problem
=
+| Monospace
+ TODO: Static tree example
+
+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"
+ ]
+ |> 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
+ ]
+
+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
+ ]
+
=| Note
- *We are still working on this content.*
+ 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).
=
- Stay tuned {Icon|name=radio}
+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
+
+| 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:
+
+| 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:
+
+| Note
+ TODO: Example
+
+It's already starts to look interesting, but there are two problems with it. First it doesn't fit on screen. This is easy to fix using {Code|viewBox}. We need to zoom out to see more of a picture. Change the value passed to {Code|viewBox} on line 19 to {Code|"-500 -500 1000 1000"}, effectively zooming out 5x but preserving keeping the origin in the center of our viewbox.
+
+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
+ ]
+ , dot color rotation
+ , line color rotation
+ ]
+
+With this two changes applied you should see something like this in the browser:
+
+| Note
+ TODO: Example
+
+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)
+
+ 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
+ ]
+ , 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
+ ]
+
+
+ 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
+ , ")"
+ ]
+ )
+ ]
+ []
+
+
+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.
+
+Once all changes are applied, reload the browser and see that only first, skyblue segment has child segments.
+
+| Note
+ TODO: Example
+
+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
+ ]
+
+with:
+
+| 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:
+
+| 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 []
+ ]
+ |> 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
+ ]
+
+
+ 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
+ , ")"
+ ]
+ )
+ ]
+ []
+
+| Emphasize
+ Time to play 🌳🌲🌴🎄
+
+| Emphasize
+
+ Try building your own tree this way. Play with colors and sizes.
+
+| Note
+ Hint: if you add {Code|Svg.attributes.strokeWidth "2"} attribute to the line, you will get thicker branches. Try different combinations of stroke width and radius of a dot.Start writing Rule Based Tree
index 80d31eb..3dbc52a 100644
--- a/content/day-4.txt
+++ b/content/day-4.txt
@@ -370,3 +370,30 @@ A segment within a segment! Consider that every segment can have child segments.
=
=| Note
= Hint: if you add {Code|Svg.attributes.strokeWidth "2"} attribute to the line, you will get thicker branches. Try different combinations of stroke width and radius of a dot.
+
+| Header
+ Rules Based Tree
+
+I hope you had fun and are proud of your tree. If you made a big one, perhaps you have noticed that all this nesting gets pretty tedious. What if we could make the computer do the hard work? We can do it, but as you may have noticed computers are not very smart, so we need to give them exact rules.
+
+Let's say we have three types of segments: brown, green and red. The child segments depend on the parent like this:
+
+| List
+ #. We always start with a brown segment going up (-90 degree).
+
+ #. The brown segment will have three green child segments:
+
+ - one going straight (0 degrees),
+ - one a little bit to the right (20 degree)
+ - and one little bit to the left (-30 degree).
+
+ #. Green segments will have three red child segments
+
+ - one at -45 degree
+ - one at -5 degree
+ - one at 50 degree
+
+The tree following these rules will look like this:
+
+| Note
+ TODO: ExampleUpgrade mdgriffith/elm-markup to 2.0.6
Fixed startWith bugs.
index 439720e..64c0692 100644
--- a/elm.json
+++ b/elm.json
@@ -22,7 +22,7 @@
= "feathericons/elm-feather": "1.3.0",
= "ianmackenzie/elm-geometry": "1.2.1",
= "ianmackenzie/elm-geometry-svg": "1.0.2",
- "mdgriffith/elm-markup": "2.0.5",
+ "mdgriffith/elm-markup": "2.0.6",
= "mdgriffith/elm-ui": "1.1.0",
= "turboMaCk/any-dict": "1.0.1"
= },