Skip to content

Instantly share code, notes, and snippets.

@toburger
Created February 14, 2020 10:28
Show Gist options
  • Select an option

  • Save toburger/700e96a42a71fc9676170c8f484ca5fe to your computer and use it in GitHub Desktop.

Select an option

Save toburger/700e96a42a71fc9676170c8f484ca5fe to your computer and use it in GitHub Desktop.

Revisions

  1. toburger created this gist Feb 14, 2020.
    181 changes: 181 additions & 0 deletions fable-repl.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,181 @@
    module Recharts

    open Fable.Core.JsInterop
    open Fable.Recharts
    open Fable.Recharts.Props
    open Fable.React
    open Elmish
    open Elmish.React
    module R = Fable.React.Standard
    module P = Fable.React.Props
    module H = Fable.React.Helpers

    type PieData =
    { name: string
    value: int }

    let pieData = [|
    { name= "Group A"; value= 400 }
    { name= "Group B"; value= 300 }
    { name= "Group C"; value= 300 }
    { name= "Group D"; value= 200 }
    |]

    type Model =
    { Data: PieData array
    ActiveIndex: int }

    type Msg =
    | Refresh
    | SetActiveIndex of int

    let init () =
    { Data = pieData
    ActiveIndex = 0 },
    Cmd.none

    // UPDATE

    let rnd =
    let random = System.Random()
    fun min max -> random.Next(min, max)

    let randomizePieData (data: PieData) =
    { data with value = rnd 200 800 }

    let update (msg:Msg) (model:Model) =
    match msg with
    | Refresh ->
    { model with Data = pieData |> Array.map randomizePieData }, Cmd.none
    | SetActiveIndex index ->
    { model with ActiveIndex = index }, Cmd.none

    // VIEW (rendered with React)

    type ActiveShapeProps =
    { cy: float
    cx: float
    midAngle: float
    innerRadius: float
    outerRadius: float
    startAngle: float
    endAngle: float
    fill: string
    payload: obj
    percent: float
    value: float }

    type Pie =
    | ActiveIndex of int
    | ActiveShape of (ActiveShapeProps -> ReactElement)
    | OnMouseEnter of (obj -> int -> unit)
    interface P.IProp

    let renderActiveShape (props: ActiveShapeProps) =
    let radian = System.Math.PI / 180.
    let sin = sin (-radian * props.midAngle)
    let cos = cos (-radian * props.midAngle)
    let sx = props.cx + (props.outerRadius + 10.) * cos
    let sy = props.cy + (props.outerRadius + 10.) * sin
    let mx = props.cx + (props.outerRadius + 30.) * cos
    let my = props.cy + (props.outerRadius + 30.) * sin
    let ex = mx + (if cos >= 0. then 1. else -1.) * 22.
    let ey = my
    let textAnchor = if cos >= 0. then "start" else "end"
    R.g [] [
    text [
    P.X props.cx
    P.Y props.cy
    P.Dy 8.
    Text.TextAnchor "middle"
    P.Fill props.fill
    ] [
    H.str props.payload?name
    ]
    sector [
    Polar.Cx props.cx
    Polar.Cy props.cy
    Polar.InnerRadius props.innerRadius
    Polar.OuterRadius props.outerRadius
    Polar.StartAngle props.startAngle
    Polar.EndAngle props.endAngle
    P.Fill props.fill
    ]
    sector [
    Polar.Cx props.cx
    Polar.Cy props.cy
    Polar.StartAngle props.startAngle
    Polar.EndAngle props.endAngle
    Polar.InnerRadius (props.outerRadius + 6.)
    Polar.OuterRadius (props.outerRadius + 10.)
    P.Fill props.fill
    ]
    R.path [
    P.D (sprintf "M%f,%fL%f,%fL%f,%f" sx sy mx my ex ey)
    P.Stroke props.fill
    P.Fill "none"
    ] []
    R.circle [
    Polar.Cx ex
    Polar.Cy ey
    P.R 2.
    P.Fill props.fill
    P.Stroke "none"
    ] []
    text [
    P.X (ex + (if cos >= 0. then 1. else -1.) * 12.)
    P.Y ey
    Text.TextAnchor textAnchor
    P.Fill "#333"
    ] [
    H.str (sprintf "PV %.0f" props.value)
    ]
    text [
    P.X (ex + (if cos >= 0. then 1. else -1.) * 12.)
    P.Y ey
    P.Dy 18.
    Text.TextAnchor textAnchor
    P.Fill "#999"
    ] [
    H.str (sprintf "(Rate %.2f%%)" props.percent)
    ]
    ]

    let view model dispatch =
    R.div [] [
    R.h1 [] [
    H.str "Sample with Recharts and Elmish"
    ]
    R.p [] [
    H.str "Ported from: http://recharts.org/en-US/examples/CustomActiveShapePieChart"
    ]
    R.button [
    P.OnClick (fun _ -> dispatch Refresh)
    ] [ H.str "Refresh" ]
    pieChart [
    Chart.Width 800.
    Chart.Height 400.
    ] [
    pie [
    Polar.DataKey "value"
    Pie.ActiveIndex model.ActiveIndex
    Pie.ActiveShape renderActiveShape
    Polar.Data model.Data
    //Polar.AnimationBegin 10.
    //Polar.AnimationDuration 500.
    Polar.Cx 300.
    Polar.Cy 200.
    Polar.InnerRadius 60.
    Polar.OuterRadius 80.
    P.Fill "#8884d8"
    Pie.OnMouseEnter (fun _ index ->
    dispatch (SetActiveIndex (int index)))
    ] []
    ]
    ]

    // App
    Program.mkProgram init update view
    |> Program.withConsoleTrace
    |> Program.withReact "elmish-app"
    |> Program.run
    16 changes: 16 additions & 0 deletions fable-repl.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    <!doctype html>
    <html>
    <head>
    <title>Fable + Recharts</title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="__HOST__/libs/react.production.min.js"></script>
    <script src="__HOST__/libs/react-dom.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/[email protected]/prop-types.min.js"></script>
    <script crossorigin src="https://unpkg.com/[email protected]/umd/Recharts.min.js"></script>
    </head>
    <body>
    <div id="elmish-app"></div>
    <script src="bundle.js"></script>
    </body>
    </html>