Something went wrong. Try again.
Graphics calculator made with elm tedius.tngl.sh/zero
elm math graphics
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230module Main exposing (..)
import Browserimport Browser.Dom as Domimport Browser.Eventsimport Draw exposing (ZeroSvg, mainSvg)import Html exposing (Html, a, button, div, img, input, p, text)import Html.Attributes exposing (..)import Html.Events exposing (on, onClick, onInput, onSubmit)import Json.Decode as Decodeimport List exposing (filter, member)import Parse exposing (Point(..), Vector(..), deadEndsToString, point, pointToString, vector, vectorToString)import Parser exposing (Parser, oneOf, run)import Task
-- MAIN
main : Program () Model Msgmain = Browser.element { init = init, update = update, view = view, subscriptions = subscriptions }
-- MODEL
type alias Model = { points : List Point , vectors : List Vector , inputText : String , parseError : String , svg : ZeroSvg }
init : () -> ( Model, Cmd Msg )init _ = ( { points = [ Point { name = "A", x = 5, y = 10 } ] , vectors = [ Vector { name = "u", x = -3, y = 5 } ] , inputText = "" , parseError = "" , svg = { size = { width = 800.0, height = 600.0 } , center = { x = 0.0, y = 0.0 } , scale = 20.0 } } , getSvgSizeCmd )
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msgsubscriptions model = Browser.Events.onResize (\_ _ -> GetSvgSize)
-- UPDATE
onWheel : (Float -> msg) -> Html.Attribute msgonWheel tagger = on "wheel" (Decode.map tagger (Decode.at [ "deltaY" ] Decode.float))
type Msg = Add | DeletePoint Point | DeleteVector Vector | UpdateInput String | GetSvgSize | GotSvgSize (Result Dom.Error Dom.Element) | WheelMoved Float
getSvgSizeCmd : Cmd MsggetSvgSizeCmd = Task.attempt GotSvgSize (Dom.getElement "svg")
update : Msg -> Model -> ( Model, Cmd Msg )update msg model = case msg of UpdateInput text -> ( { model | inputText = text }, Cmd.none )
Add -> if model.inputText /= "" then case run (parserMaster model) model.inputText of Ok newModel -> ( newModel, Cmd.none )
Err err -> ( { model | parseError = deadEndsToString err }, Cmd.none )
else ( model, Cmd.none )
DeletePoint pointToDelete -> ( { model | points = filter (areDifferentPoint pointToDelete) model.points }, Cmd.none )
DeleteVector vectorToDelete -> ( { model | vectors = filter (areDifferentVector vectorToDelete) model.vectors }, Cmd.none )
GetSvgSize -> ( model, getSvgSizeCmd )
GotSvgSize (Ok element) -> let svg = model.svg
updatedSvg = { svg | size = { width = element.element.width, height = element.element.height } } in ( { model | svg = updatedSvg } , Cmd.none )
GotSvgSize (Err _) -> ( model, getSvgSizeCmd )
WheelMoved moved -> let svg = model.svg
newScale = svg.scale * (1 - moved / 1000)
updatedSvg = { svg | scale = clamp 1 1000 newScale } in ( { model | svg = updatedSvg } , Cmd.none )
parserMaster : Model -> Parser ModelparserMaster model = oneOf [ Parser.map (\p -> if member p model.points then { model | parseError = "Duplicate Point" }
else { model | points = p :: model.points, inputText = "" } ) point , Parser.map (\v -> if member v model.vectors then { model | parseError = "Duplicate Vector" }
else { model | vectors = v :: model.vectors, inputText = "" } ) vector ]
areDifferentPoint : Point -> Point -> BoolareDifferentPoint (Point p1) (Point p2) = p1.name /= p2.name
areDifferentVector : Vector -> Vector -> BoolareDifferentVector (Vector v1) (Vector v2) = v1.name /= v2.name
-- VIEW
pointToDiv : Point -> Html MsgpointToDiv point = div [ class "entry" ] [ div [ class "entry-text" ] [ text (pointToString point) ] , button [ class "minus-button", onClick (DeletePoint point) ] [ text "-" ] ]
vectorToDiv : Vector -> Html MsgvectorToDiv vector = div [ class "entry" ] [ div [ class "entry-text" ] [ text (vectorToString vector) ] , button [ class "minus-button", onClick (DeleteVector vector) ] [ text "-" ] ]
errorToDiv : String -> Html MsgerrorToDiv error = div [ class "error" ] [ text error ]
socialsDiv : Html MsgsocialsDiv = a [ class "socials", target "_black", href "https://github.com/tedius-git/zero" ] [ img [ src "./src/assets/github-mark.svg", style "height" "30px" ] [] ]
viewInput : String -> Html MsgviewInput inputText = Html.form [ class "add", onSubmit Add ] [ input [ class "add-input", value inputText, onInput UpdateInput ] [], button [ class "plus-button", onClick Add ] [ text "+" ] ]
view : Model -> Html Msgview model = div [ class "app" ] [ div [ class "input" ] [ viewInput model.inputText , div [] [ errorToDiv model.parseError ] , div [] (List.reverse (List.map pointToDiv model.points)) , div [] (List.reverse (List.map vectorToDiv model.vectors)) , div [ class "spacer" ] [] , socialsDiv ] , div [ id "svg", onWheel WheelMoved ] [ mainSvg model.svg model.points model.vectors ] ]