diff --git a/public/main.js b/public/main.js index 808cabce90662c7fa1e742119e1140fd8548901f..5f923ed4a999231679a1d12b1457bdcd31575c0b 100644 --- a/public/main.js +++ b/public/main.js @@ -5539,6 +5539,155 @@ var $author$project$BoundedInt$change = F2( boundedInt, {value: value}); }); +var $elm$core$String$fromFloat = _String_fromNumber; +var $elm$svg$Svg$Attributes$height = _VirtualDom_attribute('height'); +var $elm$core$Basics$pow = _Basics_pow; +var $elm$core$Basics$sqrt = _Basics_sqrt; +var $elm$svg$Svg$trustedNode = _VirtualDom_nodeNS('http://www.w3.org/2000/svg'); +var $elm$svg$Svg$svg = $elm$svg$Svg$trustedNode('svg'); +var $author$project$Main$toDotPosition = F4( + function (size, gap, offset, id) { + var marginalIncrease = (size + gap) / 2; + return _Utils_Tuple2((id * marginalIncrease) + offset, (((id + 1) % 2) * marginalIncrease) + offset); + }); +var $author$project$Main$boolAsIntString = function (bool) { + return bool ? '1' : '0'; +}; +var $elm$core$String$concat = function (strings) { + return A2($elm$core$String$join, '', strings); +}; +var $elm$svg$Svg$Attributes$fill = _VirtualDom_attribute('fill'); +var $elm$svg$Svg$Attributes$fillOpacity = _VirtualDom_attribute('fill-opacity'); +var $elm$core$List$intersperse = F2( + function (sep, xs) { + if (!xs.b) { + return _List_Nil; + } else { + var hd = xs.a; + var tl = xs.b; + var step = F2( + function (x, rest) { + return A2( + $elm$core$List$cons, + sep, + A2($elm$core$List$cons, x, rest)); + }); + var spersed = A3($elm$core$List$foldr, step, _List_Nil, tl); + return A2($elm$core$List$cons, hd, spersed); + } + }); +var $elm$core$Tuple$mapBoth = F3( + function (funcA, funcB, _v0) { + var x = _v0.a; + var y = _v0.b; + return _Utils_Tuple2( + funcA(x), + funcB(y)); + }); +var $elm$core$Tuple$mapFirst = F2( + function (func, _v0) { + var x = _v0.a; + var y = _v0.b; + return _Utils_Tuple2( + func(x), + y); + }); +var $elm$core$Tuple$mapSecond = F2( + function (func, _v0) { + var x = _v0.a; + var y = _v0.b; + return _Utils_Tuple2( + x, + func(y)); + }); +var $elm$svg$Svg$Attributes$points = _VirtualDom_attribute('points'); +var $elm$svg$Svg$polygon = $elm$svg$Svg$trustedNode('polygon'); +var $elm$core$Tuple$second = function (_v0) { + var y = _v0.b; + return y; +}; +var $elm$svg$Svg$Attributes$stroke = _VirtualDom_attribute('stroke'); +var $elm$svg$Svg$Attributes$strokeWidth = _VirtualDom_attribute('stroke-width'); +var $author$project$Main$tupleToString = function (tuple) { + var second = $elm$core$String$fromFloat(tuple.b); + var first = $elm$core$String$fromFloat(tuple.a); + return first + (',' + second); +}; +var $author$project$Main$viewDot = F4( + function (size, strokeWidth, isFilled, position) { + return A2( + $elm$svg$Svg$polygon, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$points( + $elm$core$String$concat( + A2( + $elm$core$List$intersperse, + ' ', + A2( + $elm$core$List$map, + $author$project$Main$tupleToString, + A2( + $elm$core$List$map, + $elm$core$Tuple$mapSecond( + $elm$core$Basics$add(position.b)), + A2( + $elm$core$List$map, + $elm$core$Tuple$mapFirst( + $elm$core$Basics$add(position.a)), + A2( + $elm$core$List$map, + A2( + $elm$core$Tuple$mapBoth, + $elm$core$Basics$mul(size), + $elm$core$Basics$mul(size)), + _List_fromArray( + [ + _Utils_Tuple2(0.5, 0.0), + _Utils_Tuple2(1.0, 0.5), + _Utils_Tuple2(0.5, 1.0), + _Utils_Tuple2(0.0, 0.5) + ])))))))), + $elm$svg$Svg$Attributes$fill('var(--bulma-body-color)'), + $elm$svg$Svg$Attributes$fillOpacity( + $author$project$Main$boolAsIntString(isFilled)), + $elm$svg$Svg$Attributes$stroke('var(--bulma-body-color)'), + $elm$svg$Svg$Attributes$strokeWidth( + $elm$core$String$fromFloat(strokeWidth)) + ]), + _List_Nil); + }); +var $elm$svg$Svg$Attributes$width = _VirtualDom_attribute('width'); +var $author$project$Main$viewDots = F2( + function (totalDotCount, filledDotCount) { + var isFilledList = A2( + $elm$core$List$map, + $elm$core$Basics$gt(filledDotCount), + A2($elm$core$List$range, 0, totalDotCount - 1)); + var dotSize = 12; + var dotOutline = 0.05 * dotSize; + var svgOutlineMargin = $elm$core$Basics$sqrt( + 2 * A2($elm$core$Basics$pow, dotOutline, 2)) / 2; + var dotGap = 4; + var marginalIncrease = (dotSize + dotGap) / 2; + return A2( + $elm$svg$Svg$svg, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$width( + $elm$core$String$fromFloat((dotSize + (marginalIncrease * (totalDotCount - 1))) + (2 * svgOutlineMargin))), + $elm$svg$Svg$Attributes$height( + $elm$core$String$fromFloat((dotSize + marginalIncrease) + (2 * svgOutlineMargin))) + ]), + A3( + $elm$core$List$map2, + A2($author$project$Main$viewDot, dotSize, dotOutline), + isFilledList, + A2( + $elm$core$List$map, + A3($author$project$Main$toDotPosition, dotSize, dotGap, svgOutlineMargin), + A2($elm$core$List$range, 0, totalDotCount - 1)))); + }); var $author$project$Main$viewSphere = function (sphere) { return A2( $elm$html$Html$div, @@ -5574,8 +5723,7 @@ var $author$project$Main$viewSphere = function (sphere) { _List_Nil, _List_fromArray( [ - $elm$html$Html$text( - $elm$core$String$fromInt(sphere.dots.value)) + A2($author$project$Main$viewDots, sphere.dots.max, sphere.dots.value) ])), A2( $elm$html$Html$button, diff --git a/src/Main.elm b/src/Main.elm index 7ccda3f44c4fc175e302400803870abc897f9e78..c6408aad85790f2fa5ad53c7f81ca6444754ddd2 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -4,6 +4,8 @@ import Browser import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) +import Svg exposing (svg) +import Svg.Attributes import Character exposing (Character) import Sphere exposing (Sphere) import BoundedInt exposing (BoundedInt) @@ -114,7 +116,7 @@ viewSphere sphere = [ class "button is-small" , onClick ( ChangeSphere { sphere | dots = BoundedInt.change sphere.dots (sphere.dots.value - 1) } ) ] [ text "-" ] - , span [] [ text ( String.fromInt sphere.dots.value ) ] + , span [] [ viewDots sphere.dots.max sphere.dots.value ] , button [ class "button is-small" , onClick ( ChangeSphere { sphere | dots = BoundedInt.change sphere.dots (sphere.dots.value + 1) } ) @@ -171,6 +173,71 @@ modalValue modalType character = case modalType of Name -> character.name +viewDots : Int -> Int -> Html Msg +viewDots totalDotCount filledDotCount = + let + dotSize = 12 + dotGap = 4 + dotOutline = 0.05 * dotSize + marginalIncrease = ( dotSize + dotGap ) / 2 + svgOutlineMargin = ( sqrt ( 2 * ( dotOutline ^ 2 ) ) ) / 2 + + isFilledList = List.range 0 ( totalDotCount - 1 ) |> List.map ( (>) filledDotCount ) + in + svg + [ Svg.Attributes.width ( String.fromFloat ( dotSize + marginalIncrease * toFloat ( totalDotCount - 1 ) + 2 * svgOutlineMargin ) ) + , Svg.Attributes.height ( String.fromFloat ( dotSize + marginalIncrease + 2 * svgOutlineMargin ) ) + ] + ( List.range 0 ( totalDotCount - 1 ) + |> List.map ( toDotPosition dotSize dotGap svgOutlineMargin ) + |> List.map2 ( viewDot dotSize dotOutline ) isFilledList + ) + +toDotPosition : Float -> Float -> Float -> Int -> ( Float, Float ) +toDotPosition size gap offset id = + let + marginalIncrease = ( size + gap ) / 2 + in + ( toFloat id * marginalIncrease + offset + , toFloat ( remainderBy 2 ( id + 1 ) ) * marginalIncrease + offset + ) + +viewDot : Float -> Float -> Bool -> ( Float, Float ) -> Html Msg +viewDot size strokeWidth isFilled position = + Svg.polygon + [ Svg.Attributes.points + ( [ ( 0.5, 0.0 ) + , ( 1.0, 0.5 ) + , ( 0.5, 1.0 ) + , ( 0.0, 0.5 ) + ] + |> List.map ( Tuple.mapBoth ( (*) size ) ( (*) size ) ) + |> List.map ( Tuple.mapFirst ( (+) ( Tuple.first position ) ) ) + |> List.map ( Tuple.mapSecond ( (+) ( Tuple.second position ) ) ) + |> List.map tupleToString + |> List.intersperse " " + |> String.concat + ) + , Svg.Attributes.fill "var(--bulma-body-color)" + , Svg.Attributes.fillOpacity ( boolAsIntString isFilled ) + , Svg.Attributes.stroke "var(--bulma-body-color)" + , Svg.Attributes.strokeWidth ( String.fromFloat strokeWidth ) + ] [] + +tupleToString : ( Float, Float ) -> String +tupleToString tuple = + let + first = String.fromFloat ( Tuple.first tuple ) + second = String.fromFloat ( Tuple.second tuple ) + in + first ++ "," ++ second + +boolAsIntString : Bool -> String +boolAsIntString bool = + if bool + then "1" + else "0" + subscriptions : Model -> Sub Msg subscriptions _ = Sub.none