Skip to content

Instantly share code, notes, and snippets.

@readysetmark
Created February 6, 2016 04:41
Show Gist options
  • Select an option

  • Save readysetmark/7e5cfed1f6277e152cb9 to your computer and use it in GitHub Desktop.

Select an option

Save readysetmark/7e5cfed1f6277e152cb9 to your computer and use it in GitHub Desktop.
BMI calculator in Elm
import Html exposing (Html, Attribute, div, h2, input, text)
import Html.Attributes exposing (class, type')
import Html.Events exposing (on, targetValue)
import Signal exposing (Address)
import String exposing (toLower, toInt)
import StartApp.Simple as StartApp
-- HELPERS
toFixed : Int -> Float -> Float
toFixed precision num =
let modifier = (10^precision)
rounded =
num * modifier
|> round
|> toFloat
in
rounded / modifier
bmi : Int -> Int -> Float
bmi weight height =
let w = toFloat weight
h = (toFloat height) * 0.01
bmi = w / (h^2)
in
toFixed 2 bmi
onInput : Address a -> (String -> a) -> Attribute
onInput address f =
on "input" targetValue (\v -> Signal.message address (f v))
parseInt : Int -> String -> Int
parseInt default string =
Result.withDefault default (toInt string)
-- MODEL
type alias LabeledSlider =
{ label: String
, unit: String
, min: Int
, max: Int
, value: Int
}
type alias Model =
{ weightSlider: LabeledSlider
, heightSlider: LabeledSlider
, bmi : Float
}
newLabeledSlider : String -> String -> Int -> Int -> Int -> LabeledSlider
newLabeledSlider label unit min max value =
{ label = label
, unit = unit
, min = min
, max = max
, value = value
}
initialWeight : Int
initialWeight = 70
initialHeight : Int
initialHeight = 160
initialModel : Model
initialModel =
{ weightSlider = newLabeledSlider "Weight" "kg" 40 140 initialWeight
, heightSlider = newLabeledSlider "Height" "cm" 70 220 initialHeight
, bmi = bmi initialWeight initialHeight
}
-- UPDATE
type Action
= NoOp
| WeightChanged Int
| HeightChanged Int
update : Action -> Model -> Model
update action model =
case action of
NoOp ->
model
WeightChanged newWeight ->
let weightSlider' = model.weightSlider
weightSlider = { weightSlider' | value = newWeight }
bmi' = bmi weightSlider.value model.heightSlider.value
in { model | weightSlider = weightSlider, bmi = bmi' }
HeightChanged newHeight ->
let heightSlider' = model.heightSlider
heightSlider = { heightSlider' | value = newHeight }
bmi' = bmi model.weightSlider.value heightSlider.value
in { model | heightSlider = heightSlider, bmi = bmi' }
-- VIEW
labeledSlider : Address Action -> LabeledSlider -> (String -> Action) -> Html
labeledSlider address slider createAction =
div [ ]
[ text (slider.label ++ " " ++ (toString slider.value) ++ slider.unit)
, input
[ class (toLower slider.label)
, type' "range"
, Html.Attributes.min (toString slider.min)
, Html.Attributes.max (toString slider.max)
, Html.Attributes.value (toString slider.value)
, onInput address createAction
]
[]
]
bmiResult : Float -> Html
bmiResult bmi =
h2 [ ] [ text ("BMI is " ++ (toString bmi)) ]
view : Address Action -> Model -> Html
view address model =
div []
[ labeledSlider address model.weightSlider (\value -> WeightChanged (parseInt 1 value))
, labeledSlider address model.heightSlider (\value -> HeightChanged (parseInt 1 value))
, bmiResult model.bmi
]
-- WIRING
main : Signal Html
main =
StartApp.start
{ model = initialModel
, view = view
, update = update
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment