diff --git a/public/index.html b/public/index.html
index e64053d..410c5ad 100644
--- a/public/index.html
+++ b/public/index.html
@@ -24,6 +24,24 @@
background-color: rgb(0,0,16);
display: inline-block;
}
+
+ .slider-group > * {
+ margin-top: 1em;
+ }
+
+ .labelled-slider {
+ width: 100%;
+ display: flex;
+ }
+ .labelled-slider input[type=range] {
+ width: 100%;
+ flex-grow: 1;
+ align-self: center;
+ }
+ .labelled-slider span {
+ width: 5ex;
+ }
+
@media screen and (max-width:430px) {
html, body,
.tile {
diff --git a/public/index.html b/public/index.html
index e64053d..410c5ad 100644
--- a/public/index.html
+++ b/public/index.html
@@ -24,6 +24,24 @@
background-color: rgb(0,0,16);
display: inline-block;
}
+
+ .slider-group > * {
+ margin-top: 1em;
+ }
+
+ .labelled-slider {
+ width: 100%;
+ display: flex;
+ }
+ .labelled-slider input[type=range] {
+ width: 100%;
+ flex-grow: 1;
+ align-self: center;
+ }
+ .labelled-slider span {
+ width: 5ex;
+ }
+
@media screen and (max-width:430px) {
html, body,
.tile {
diff --git a/src/Main.elm b/src/Main.elm
index 2dd3776..73451f4 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,6 +1,9 @@
module Main exposing (..)
+import Browser
import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
import Svg exposing (..)
import Svg.Attributes exposing (..)
@@ -33,27 +36,51 @@
Point p.y -p.x
-tip line =
+tip tipHeight line =
diff line.start line.end
|> rotateMinus90Deg
- |> scale (sqrt 3 / 6)
+ |> scale ((sqrt 3 / 6) * tipHeight)
|> add (midpoint 0.5 line)
-kochDivide line =
- [ Line line.start (midpoint (1 / 3) line)
- , Line (midpoint (1 / 3) line) (tip line)
- , Line (tip line) (midpoint (2 / 3) line)
- , Line (midpoint (2 / 3) line) line.end
+kochMidPoints tipHeight gapWidth line =
+ [ line.start
+ , midpoint (0.5 - gapWidth / 2.0) line
+ , tip tipHeight line
+ , midpoint (0.5 + gapWidth / 2.0) line
+ , line.end
]
-kochIteration iterations lineList =
+pointListToLinesRec firstPoint remainingPoints lines =
+ case remainingPoints of
+ p :: ps ->
+ pointListToLinesRec p ps (Line firstPoint p :: lines)
+
+ [] ->
+ lines
+
+
+pointListToLines points =
+ case points of
+ p :: ps ->
+ pointListToLinesRec p ps []
+
+ [] ->
+ []
+
+
+kochDivide tipHeight gapWidth line =
+ line |> kochMidPoints tipHeight gapWidth |> pointListToLines
+
+
+kochIteration iterations model lineList =
if iterations == 0 then
lineList
else
- List.concatMap kochDivide lineList |> kochIteration (iterations - 1)
+ List.concatMap (kochDivide model.tipHeight model.gapWidth) lineList
+ |> kochIteration (iterations - 1) model
lineToSvg : Line -> Svg.Svg msg
@@ -68,22 +95,109 @@
baseHeight =
- 250
+ 200
startLine =
- Line (Point 0 baseHeight) (Point 400 baseHeight)
+ Line (Point 50 baseHeight) (Point 350 baseHeight)
-main =
- div [ class "tile" ]
+type alias Model =
+ { gapWidth : Float
+ , tipHeight : Float
+ , iterations : Float
+ }
+
+
+type alias LabelledSliderParameters =
+ { id : String
+ , label : String
+ , min : Float
+ , max : Float
+ , step : Float
+ }
+
+
+roundToPrecision : Int -> Float -> Float
+roundToPrecision precision number =
+ toFloat (round (number * toFloat (10 ^ precision))) / toFloat (10 ^ precision)
+
+
+labelledSlider params msg modelValue =
+ div [ Html.Attributes.class "labelled-slider" ]
+ [ label [ for params.id ] [ Html.text params.label ]
+ , input
+ [ Html.Attributes.id params.id
+ , Html.Attributes.type_ "range"
+ , Html.Attributes.min <| String.fromFloat params.min
+ , Html.Attributes.max <| String.fromFloat params.max
+ , Html.Attributes.step <| String.fromFloat params.step
+ , Html.Attributes.value <| String.fromFloat modelValue
+ , onInput msg
+ ]
+ []
+ , span [] [modelValue |> roundToPrecision 2 |> String.fromFloat |> Html.text]
+ ]
+
+
+view : Model -> Html Msg
+view model =
+ div [ Html.Attributes.class "tile" ]
[ h2 [] [ Html.text "Koch" ]
, div []
[ svg
- [ width "400px"
- , height "400px"
+ [ Svg.Attributes.width "400px"
+ , Svg.Attributes.height "400px"
, Svg.Attributes.style "fill: none; stroke: purple; stroke-width: 1;"
]
- ([ startLine ] |> kochIteration 5 |> List.map lineToSvg)
+ ([ startLine ] |> kochIteration model.iterations model |> List.map lineToSvg)
+ ]
+ , div [ Html.Attributes.class "slider-group" ]
+ [ labelledSlider { id = "tipHeight", label = "Tip: ", min = -3, max = 3, step = 0.01 } ChangeTipHeight model.tipHeight
+ , labelledSlider { id = "gapWidth", label = "Gap: ", min = -3, max = 3, step = 0.01 } ChangeGapWidth model.gapWidth
+ , labelledSlider { id = "iterations", label = "Iterations: ", min = 0, max = 6, step = 1 } ChangeIterations model.iterations
]
]
+
+
+init : Model
+init =
+ { gapWidth = 1 / 3, tipHeight = 1, iterations = 5 }
+
+
+type Msg
+ = ChangeGapWidth String
+ | ChangeTipHeight String
+ | ChangeIterations String
+
+
+update : Msg -> Model -> Model
+update msg model =
+ case msg of
+ ChangeGapWidth newWidth ->
+ case String.toFloat newWidth of
+ Just w ->
+ { model | gapWidth = w }
+
+ Nothing ->
+ model
+
+ ChangeTipHeight newHeight ->
+ case String.toFloat newHeight of
+ Just h ->
+ { model | tipHeight = h }
+
+ Nothing ->
+ model
+
+ ChangeIterations newIterations ->
+ case String.toFloat newIterations of
+ Just i ->
+ { model | iterations = i }
+
+ Nothing ->
+ model
+
+
+main =
+ Browser.sandbox { view = view, update = update, init = init }