Skip to content

Instantly share code, notes, and snippets.

@toburger
Created February 14, 2020 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toburger/700e96a42a71fc9676170c8f484ca5fe to your computer and use it in GitHub Desktop.
Save toburger/700e96a42a71fc9676170c8f484ca5fe to your computer and use it in GitHub Desktop.
Created with Fable REPL
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
<!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/prop-types@15.7.2/prop-types.min.js"></script>
<script crossorigin src="https://unpkg.com/recharts@1.8.5/umd/Recharts.min.js"></script>
</head>
<body>
<div id="elmish-app"></div>
<script src="bundle.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment