desck 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +21 -0
- package/README.md +176 -0
- package/desck.cjs +2 -0
- package/elm.json +39 -0
- package/justfile +13 -0
- package/package.json +25 -0
- package/public/index.html +30 -0
- package/public/palette.json +16 -0
- package/public/projects/something.json +139 -0
- package/public/projects/template.json +69 -0
- package/public/script.js +490 -0
- package/public/style.css +471 -0
- package/public/svg/backface.svg +1 -0
- package/public/svg/courts.svg +30 -0
- package/public/svg/digits.svg +18 -0
- package/public/svg/suits.svg +43 -0
- package/server.cjs +316 -0
- package/settings.json +10 -0
- package/src/Card.elm +38 -0
- package/src/ColorPicker.elm +113 -0
- package/src/Deck.elm +571 -0
- package/src/DeckView.elm +415 -0
- package/src/Layout.elm +224 -0
- package/src/Main.elm +3743 -0
- package/src/Palette.elm +302 -0
- package/src/Project.elm +1029 -0
- package/src/Rect.elm +292 -0
- package/src/SaveFile.elm +422 -0
- package/src/Theme.elm +99 -0
- package/src/Util.elm +337 -0
- package/src/Vec.elm +196 -0
- package/src/Zone.elm +364 -0
package/src/Theme.elm
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Theme exposing (..)
|
|
2
|
+
|
|
3
|
+
import Palette exposing (Palette)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
defaultPalette : Palette
|
|
7
|
+
defaultPalette =
|
|
8
|
+
{ black = "#111111"
|
|
9
|
+
, white = "#eeeeee"
|
|
10
|
+
, red = "#df0000"
|
|
11
|
+
, orange = "#bb6600"
|
|
12
|
+
, yellow = "#ebeb0a"
|
|
13
|
+
, green = "#12be12"
|
|
14
|
+
, cyan = "#12be80"
|
|
15
|
+
, blue = "#1234de"
|
|
16
|
+
, violet = "#8212d3"
|
|
17
|
+
, pink = "#e212e2"
|
|
18
|
+
, darkGray = "#333333"
|
|
19
|
+
, midGray = "#666666"
|
|
20
|
+
, lightGray = "#aaaaaa"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
d : Palette
|
|
25
|
+
d =
|
|
26
|
+
defaultPalette
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
default : Palette
|
|
30
|
+
default =
|
|
31
|
+
d
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
dark : Palette
|
|
35
|
+
dark =
|
|
36
|
+
{ d
|
|
37
|
+
| white = d.black
|
|
38
|
+
, lightGray = d.darkGray
|
|
39
|
+
, darkGray = d.lightGray
|
|
40
|
+
, black = d.lightGray
|
|
41
|
+
, blue = d.lightGray
|
|
42
|
+
, yellow = d.darkGray
|
|
43
|
+
, red = d.red
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
ink : Palette
|
|
48
|
+
ink =
|
|
49
|
+
{ black = "#000000", white = "#ffffff", red = "#ff5252", orange = "#d64d00", yellow = "#eede4f", green = "#db6039", cyan = "#ff2305", blue = "#450b8e", violet = "#841010", pink = "#c70c00", darkGray = "#333333", midGray = "#737373", lightGray = "#cccccc" }
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
earth : Palette
|
|
53
|
+
earth =
|
|
54
|
+
{ black = "#303419", white = "#ffffff", red = "#d65f1f", orange = "#868a5c", yellow = "#ccc47f", green = "#677a48", cyan = "#222a2a", blue = "#587a1f", violet = "#412a2a", pink = "#f1bab6", darkGray = "#000000", midGray = "#758264", lightGray = "#ccdfb9" }
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
gem : Palette
|
|
58
|
+
gem =
|
|
59
|
+
{ black = "#191d34", white = "#ffffff", red = "#ff4292", orange = "#e5e4c8", yellow = "#b69aa4", green = "#152c47", cyan = "#02435f", blue = "#00648f", violet = "#602f46", pink = "#f8afc5", darkGray = "#000000", midGray = "#81cedf", lightGray = "#bcebf5" }
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
royal : Palette
|
|
63
|
+
royal =
|
|
64
|
+
{ black = "#003e52", white = "#ffffff", red = "#ff4d00", orange = "#ff7629", yellow = "#ff9900", green = "#3aa68c", cyan = "#1c5959", blue = "#008bc7", violet = "#a30000", pink = "#db4343", darkGray = "#0076a8", midGray = "#188686", lightGray = "#adfbdf" }
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
mono : Palette
|
|
68
|
+
mono =
|
|
69
|
+
{ black = "#000000", white = "#ffffff", red = "#cc2e2e", orange = "#949494", yellow = "#b8b8b8", green = "#c4c4c4", cyan = "#e6e6e6", blue = "#2b2b2b", violet = "#3b3b3b", pink = "#4f4f4f", darkGray = "#141414", midGray = "#737373", lightGray = "#cccccc" }
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
aqua : Palette
|
|
73
|
+
aqua =
|
|
74
|
+
{ black = "#000000", white = "#ffffff", red = "#21a198", orange = "#6f88b8", yellow = "#a5b7e3", green = "#8a9cff", cyan = "#ccddff", blue = "#0d2344", violet = "#002175", pink = "#2b3691", darkGray = "#010042", midGray = "#3852ad", lightGray = "#99afff" }
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
gold : Palette
|
|
78
|
+
gold =
|
|
79
|
+
{ black = "#3d1d10", white = "#7d7d7d", red = "#ddab64", orange = "#dc7138", yellow = "#d0a27c", green = "#3db872", cyan = "#5bb2be", blue = "#000000", violet = "#ad53c6", pink = "#ee8bb6", darkGray = "#141414", midGray = "#424242", lightGray = "#f5f5f5" }
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
old : Palette
|
|
83
|
+
old =
|
|
84
|
+
{ black = "#4a5440", white = "#fde6c4", red = "#e34a4a", orange = "#d6ad71", yellow = "#b58712", green = "#3b5450", cyan = "#527575", blue = "#43637a", violet = "#698996", pink = "#c48787", darkGray = "#2c2321", midGray = "#3f3631", lightGray = "#c5ac96" }
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
themes : List ( String, Palette )
|
|
88
|
+
themes =
|
|
89
|
+
[ ( "default", default )
|
|
90
|
+
, ( "dark", dark )
|
|
91
|
+
, ( "ink", ink )
|
|
92
|
+
, ( "earth", earth )
|
|
93
|
+
, ( "gem", gem )
|
|
94
|
+
, ( "royal", royal )
|
|
95
|
+
, ( "mono", mono )
|
|
96
|
+
, ( "aqua", aqua )
|
|
97
|
+
, ( "gold", gold )
|
|
98
|
+
, ( "old", old )
|
|
99
|
+
]
|
package/src/Util.elm
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
module Util exposing (..)
|
|
2
|
+
|
|
3
|
+
import Char exposing (isHexDigit, toCode)
|
|
4
|
+
import Hex
|
|
5
|
+
import Html exposing (Attribute)
|
|
6
|
+
import Json.Decode as Decode
|
|
7
|
+
import List.Extra
|
|
8
|
+
import Random exposing (Seed, initialSeed, step)
|
|
9
|
+
import Random.List
|
|
10
|
+
import Svg
|
|
11
|
+
import Svg.Attributes as A
|
|
12
|
+
import Svg.Events
|
|
13
|
+
import Vec exposing (Vec2)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
type alias Id =
|
|
17
|
+
String
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
url : String -> String
|
|
21
|
+
url s =
|
|
22
|
+
"url(#" ++ s ++ ")"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
transform : String -> List Float -> String -> String
|
|
26
|
+
transform op ls sep =
|
|
27
|
+
" "
|
|
28
|
+
++ op
|
|
29
|
+
++ "("
|
|
30
|
+
++ (ls
|
|
31
|
+
|> List.map String.fromFloat
|
|
32
|
+
|> String.join sep
|
|
33
|
+
)
|
|
34
|
+
++ ") "
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
translate : Float -> Float -> String
|
|
38
|
+
translate x y =
|
|
39
|
+
transform "translate" [ x, y ] ", "
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
translateXY : Vec2 -> String
|
|
43
|
+
translateXY pos =
|
|
44
|
+
translate pos.x pos.y
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
rotate : Float -> String
|
|
48
|
+
rotate deg =
|
|
49
|
+
transform "rotate" [ deg ] " "
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
rotateXY : Float -> Float -> Float -> String
|
|
53
|
+
rotateXY deg x y =
|
|
54
|
+
transform "rotate" [ deg, x, y ] " "
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
pivotRotate : Vec2 -> Vec2 -> Vec2 -> Float -> String
|
|
58
|
+
pivotRotate pivot pos size deg =
|
|
59
|
+
let
|
|
60
|
+
( x, y ) =
|
|
61
|
+
Vec.tuple pos
|
|
62
|
+
|
|
63
|
+
( px, py ) =
|
|
64
|
+
Vec.tuple pivot
|
|
65
|
+
|
|
66
|
+
( w, h ) =
|
|
67
|
+
Vec.tuple size
|
|
68
|
+
in
|
|
69
|
+
rotateXY deg (x + w * px) (y + h * py)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
centerRotate : Vec2 -> Vec2 -> Float -> String
|
|
73
|
+
centerRotate pos size deg =
|
|
74
|
+
let
|
|
75
|
+
( x, y ) =
|
|
76
|
+
Vec.tuple pos
|
|
77
|
+
|
|
78
|
+
( w, h ) =
|
|
79
|
+
Vec.tuple size
|
|
80
|
+
in
|
|
81
|
+
rotateXY deg (x + w / 2) (y + h / 2)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
bottomMiddleRotate : Vec2 -> Vec2 -> Float -> String
|
|
85
|
+
bottomMiddleRotate pos size deg =
|
|
86
|
+
let
|
|
87
|
+
( x, y ) =
|
|
88
|
+
Vec.tuple pos
|
|
89
|
+
|
|
90
|
+
( w, h ) =
|
|
91
|
+
Vec.tuple size
|
|
92
|
+
in
|
|
93
|
+
rotateXY deg (x + w / 2) (y + h)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
scale : Float -> String
|
|
97
|
+
scale s =
|
|
98
|
+
transform "scale" [ s ] " "
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
scaleXY : Float -> Float -> String
|
|
102
|
+
scaleXY x y =
|
|
103
|
+
transform "scale" [ x, y ] ", "
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
hexValue : Char -> Int
|
|
107
|
+
hexValue h =
|
|
108
|
+
if isHexDigit h then
|
|
109
|
+
let
|
|
110
|
+
c =
|
|
111
|
+
toCode h
|
|
112
|
+
in
|
|
113
|
+
if c >= 65 && c <= 70 then
|
|
114
|
+
c - 55
|
|
115
|
+
|
|
116
|
+
else if c >= 97 && c <= 102 then
|
|
117
|
+
c - 87
|
|
118
|
+
|
|
119
|
+
else
|
|
120
|
+
0
|
|
121
|
+
|
|
122
|
+
else
|
|
123
|
+
0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
-- else if c >= 48
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
num : (String -> Svg.Attribute msg) -> Float -> Svg.Attribute msg
|
|
131
|
+
num attr value =
|
|
132
|
+
attr (String.fromFloat value)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
shuffleList : Int -> List a -> List a
|
|
136
|
+
shuffleList seed ls =
|
|
137
|
+
step (Random.List.shuffle ls) (initialSeed seed)
|
|
138
|
+
|> Tuple.first
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
randomFloat : Int -> Float
|
|
142
|
+
randomFloat seed =
|
|
143
|
+
step (Random.float 0 1) (initialSeed seed)
|
|
144
|
+
|> Tuple.first
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
randomOffset : Int -> Float -> Float
|
|
148
|
+
randomOffset i s =
|
|
149
|
+
randomFloat i * s - s * 0.5
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
randf : Seed -> ( Float, Seed )
|
|
153
|
+
randf seed =
|
|
154
|
+
step (Random.float 0 1) seed
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
shuffleListSeed : Int -> List a -> ( List a, Seed )
|
|
158
|
+
shuffleListSeed seed ls =
|
|
159
|
+
step (Random.List.shuffle ls) (initialSeed seed)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
-- fitToScreen : { viewportWidth : Float, viewportHeight : Float, winWidth : Float, winHeight : Float } -> { x : Float, y : Float, scaledWidth : Float, scaledHeight : Float }
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
one : Vec2
|
|
167
|
+
one =
|
|
168
|
+
Vec2 1.0 1.0
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
moveTowardsLast : (a -> Bool) -> List a -> List a
|
|
172
|
+
moveTowardsLast selector list =
|
|
173
|
+
case List.Extra.splitWhen selector list of
|
|
174
|
+
Just ( before, selected :: after ) ->
|
|
175
|
+
case after of
|
|
176
|
+
[] ->
|
|
177
|
+
list
|
|
178
|
+
|
|
179
|
+
next :: rest ->
|
|
180
|
+
List.concat [ before, next :: selected :: rest ]
|
|
181
|
+
|
|
182
|
+
_ ->
|
|
183
|
+
list
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
mapNothing : (a -> b) -> Maybe a -> Maybe b -> Maybe b
|
|
187
|
+
mapNothing fn ma mb =
|
|
188
|
+
case mb of
|
|
189
|
+
Nothing ->
|
|
190
|
+
Maybe.map fn ma
|
|
191
|
+
|
|
192
|
+
Just _ ->
|
|
193
|
+
mb
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
generateDuplicateName : List String -> String -> String
|
|
197
|
+
generateDuplicateName ls s =
|
|
198
|
+
if List.member s ls then
|
|
199
|
+
generateDuplicateName ls (s ++ "_")
|
|
200
|
+
|
|
201
|
+
else
|
|
202
|
+
s
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
alwaysPreventDefault : msg -> ( msg, Bool )
|
|
206
|
+
alwaysPreventDefault msg =
|
|
207
|
+
( msg, True )
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
onRightClick : msg -> Attribute msg
|
|
211
|
+
onRightClick msg =
|
|
212
|
+
Svg.Events.preventDefaultOn "contextmenu" (Decode.map alwaysPreventDefault (Decode.succeed msg))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
-- onMiddleClick : msg -> H.Attribute msg
|
|
217
|
+
-- onMiddleClick msg =
|
|
218
|
+
-- E.on "click"
|
|
219
|
+
-- (Decode.field "button" Decode.int
|
|
220
|
+
-- |> Decode.andThen
|
|
221
|
+
-- (\button ->
|
|
222
|
+
-- if button == 1 then
|
|
223
|
+
-- Decode.succeed msg
|
|
224
|
+
-- else
|
|
225
|
+
-- Decode.fail "Not middle click"
|
|
226
|
+
-- )
|
|
227
|
+
-- )
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
onWheel : (Float -> msg) -> Attribute msg
|
|
231
|
+
onWheel decoder =
|
|
232
|
+
Svg.Events.on "wheel" (Decode.map decoder (Decode.field "deltaY" Decode.float))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
onMouseMove : (Float -> Float -> msg) -> Attribute msg
|
|
236
|
+
onMouseMove decoder =
|
|
237
|
+
Svg.Events.on "mousemove" (Decode.map2 decoder (Decode.field "offsetX" Decode.float) (Decode.field "offsetY" Decode.float))
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
type alias DragEvent =
|
|
241
|
+
{ x : Float
|
|
242
|
+
, y : Float
|
|
243
|
+
, button : Int
|
|
244
|
+
, altKey : Bool
|
|
245
|
+
, shiftKey : Bool
|
|
246
|
+
, ctrlKey : Bool
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
type MouseButton
|
|
251
|
+
= LMB
|
|
252
|
+
| MMB
|
|
253
|
+
| RMB
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
parseMouseButton : Int -> MouseButton
|
|
257
|
+
parseMouseButton i =
|
|
258
|
+
case i of
|
|
259
|
+
1 ->
|
|
260
|
+
MMB
|
|
261
|
+
|
|
262
|
+
2 ->
|
|
263
|
+
RMB
|
|
264
|
+
|
|
265
|
+
_ ->
|
|
266
|
+
LMB
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
enumDecoder : (String -> Maybe a) -> Decode.Decoder a
|
|
270
|
+
enumDecoder toEnum =
|
|
271
|
+
Decode.string
|
|
272
|
+
|> Decode.andThen
|
|
273
|
+
(\str ->
|
|
274
|
+
case toEnum str of
|
|
275
|
+
Just val ->
|
|
276
|
+
Decode.succeed val
|
|
277
|
+
|
|
278
|
+
Nothing ->
|
|
279
|
+
Decode.fail ("Invalid enum value: " ++ str)
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
positionDecoder : String -> Decode.Decoder DragEvent
|
|
284
|
+
positionDecoder s =
|
|
285
|
+
Decode.map6 DragEvent
|
|
286
|
+
(Decode.field (s ++ "X") Decode.float)
|
|
287
|
+
(Decode.field (s ++ "Y") Decode.float)
|
|
288
|
+
(Decode.field "button" Decode.int)
|
|
289
|
+
(Decode.field "altKey" Decode.bool)
|
|
290
|
+
(Decode.field "shiftKey" Decode.bool)
|
|
291
|
+
(Decode.field "ctrlKey" Decode.bool)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
offsetDecoder : Decode.Decoder DragEvent
|
|
295
|
+
offsetDecoder =
|
|
296
|
+
positionDecoder "offset"
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
colorAsTuple : String -> ( Int, Int, Int )
|
|
300
|
+
colorAsTuple color =
|
|
301
|
+
let
|
|
302
|
+
hex =
|
|
303
|
+
String.dropLeft 1 color
|
|
304
|
+
|
|
305
|
+
byte n h =
|
|
306
|
+
case Hex.fromString <| String.slice (n * 2) (n * 2 + 2) h of
|
|
307
|
+
Ok i ->
|
|
308
|
+
i
|
|
309
|
+
|
|
310
|
+
Err _ ->
|
|
311
|
+
0
|
|
312
|
+
in
|
|
313
|
+
( byte 0 hex, byte 1 hex, byte 2 hex )
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
tupleAsColor : ( Int, Int, Int ) -> String
|
|
317
|
+
tupleAsColor ( r, g, b ) =
|
|
318
|
+
"#" ++ Hex.toString r ++ Hex.toString g ++ Hex.toString b
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
tintMatrix : String -> String
|
|
322
|
+
tintMatrix color =
|
|
323
|
+
let
|
|
324
|
+
( r, g, b ) =
|
|
325
|
+
colorAsTuple color
|
|
326
|
+
in
|
|
327
|
+
(String.fromFloat <| toFloat r / 255.0) ++ " 0 0 0 0 \n0 " ++ (String.fromFloat <| toFloat g / 255.0) ++ " 0 0 0 \n0 0 " ++ (String.fromFloat <| toFloat b / 255.0) ++ " 0 0 \n0 0 0 1 0"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
tintFilter : String -> String -> Svg.Svg msg
|
|
331
|
+
tintFilter name color =
|
|
332
|
+
Svg.filter
|
|
333
|
+
[ A.id name ]
|
|
334
|
+
[ Svg.feColorMatrix
|
|
335
|
+
[ A.values <| tintMatrix color ]
|
|
336
|
+
[]
|
|
337
|
+
]
|
package/src/Vec.elm
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
module Vec exposing (..)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
type alias Vec2 =
|
|
5
|
+
{ x : Float
|
|
6
|
+
, y : Float
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
vec2 : Float -> Float -> Vec2
|
|
11
|
+
vec2 x y =
|
|
12
|
+
{ x = x, y = y }
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
add : Vec2 -> Vec2 -> Vec2
|
|
16
|
+
add a b =
|
|
17
|
+
Vec2 (a.x + b.x) (a.y + b.y)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
sub : Vec2 -> Vec2 -> Vec2
|
|
21
|
+
sub a b =
|
|
22
|
+
Vec2 (a.x - b.x) (a.y - b.y)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
scale : Float -> Vec2 -> Vec2
|
|
26
|
+
scale s a =
|
|
27
|
+
Vec2 (a.x * s) (a.y * s)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
div : Vec2 -> Vec2 -> Vec2
|
|
31
|
+
div d a =
|
|
32
|
+
Vec2 (a.x / d.x) (a.y / d.y)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
mult : Vec2 -> Vec2 -> Vec2
|
|
36
|
+
mult a b =
|
|
37
|
+
Vec2 (a.x * b.x) (a.y * b.y)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
tuple : Vec2 -> ( Float, Float )
|
|
41
|
+
tuple a =
|
|
42
|
+
( a.x, a.y )
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
fromTuple : ( Float, Float ) -> Vec2
|
|
46
|
+
fromTuple ( x, y ) =
|
|
47
|
+
{ x = x
|
|
48
|
+
, y = y
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
show : Vec2 -> String
|
|
53
|
+
show v =
|
|
54
|
+
"(" ++ (String.fromFloat <| v.x) ++ " " ++ (String.fromFloat <| v.y) ++ ")"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
half : Vec2 -> Vec2
|
|
58
|
+
half v =
|
|
59
|
+
Vec2 (v.x / 2.0) (v.y / 2.0)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
setX : Float -> Vec2 -> Vec2
|
|
63
|
+
setX x v =
|
|
64
|
+
{ v | x = x }
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
setY : Float -> Vec2 -> Vec2
|
|
68
|
+
setY y v =
|
|
69
|
+
{ v | y = y }
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
length : Vec2 -> Float
|
|
73
|
+
length v =
|
|
74
|
+
sqrt (v.x ^ 2 + v.y ^ 2)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
normalize : Vec2 -> Vec2
|
|
78
|
+
normalize v =
|
|
79
|
+
let
|
|
80
|
+
l =
|
|
81
|
+
length v
|
|
82
|
+
in
|
|
83
|
+
if l == 0 then
|
|
84
|
+
v
|
|
85
|
+
|
|
86
|
+
else
|
|
87
|
+
{ x = v.x / l, y = v.y / l }
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
direction : Vec2 -> Vec2 -> Vec2
|
|
91
|
+
direction from to =
|
|
92
|
+
sub to from |> normalize
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
distance : Vec2 -> Vec2 -> Float
|
|
96
|
+
distance a b =
|
|
97
|
+
sub b a |> length
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
lerp : Vec2 -> Vec2 -> Float -> Vec2
|
|
101
|
+
lerp a b t =
|
|
102
|
+
add (scale (1.0 - t) a) (scale t b)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
zero : Vec2
|
|
106
|
+
zero =
|
|
107
|
+
vec2 0.0 0.0
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
one : Vec2
|
|
111
|
+
one =
|
|
112
|
+
vec2 1.0 1.0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
max : Vec2 -> Vec2 -> Vec2
|
|
116
|
+
max a b =
|
|
117
|
+
vec2 (Basics.max a.x b.x) (Basics.max a.y b.y)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
min : Vec2 -> Vec2 -> Vec2
|
|
121
|
+
min a b =
|
|
122
|
+
vec2 (Basics.min a.x b.x) (Basics.min a.y b.y)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
path : Bool -> List Vec2 -> String
|
|
126
|
+
path close points =
|
|
127
|
+
let
|
|
128
|
+
ps code v =
|
|
129
|
+
" " ++ code ++ " " ++ String.fromFloat v.x ++ " " ++ String.fromFloat v.y ++ " "
|
|
130
|
+
in
|
|
131
|
+
case points of
|
|
132
|
+
first :: rest ->
|
|
133
|
+
List.foldl
|
|
134
|
+
(\v a -> a ++ ps "L" v)
|
|
135
|
+
(ps "M" first)
|
|
136
|
+
rest
|
|
137
|
+
++ (if close then
|
|
138
|
+
" Z "
|
|
139
|
+
|
|
140
|
+
else
|
|
141
|
+
""
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
_ ->
|
|
145
|
+
""
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
average : List Vec2 -> Vec2
|
|
149
|
+
average ls =
|
|
150
|
+
case ( List.head ls, List.tail ls ) of
|
|
151
|
+
( Just first, Just rest ) ->
|
|
152
|
+
let
|
|
153
|
+
l =
|
|
154
|
+
List.length ls |> toFloat
|
|
155
|
+
in
|
|
156
|
+
List.foldl (\p a -> add a p) first rest
|
|
157
|
+
|> div (vec2 l l)
|
|
158
|
+
|
|
159
|
+
( Just first, Nothing ) ->
|
|
160
|
+
first
|
|
161
|
+
|
|
162
|
+
_ ->
|
|
163
|
+
zero
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
rotate : Float -> Vec2 -> Vec2
|
|
167
|
+
rotate radians v =
|
|
168
|
+
let
|
|
169
|
+
x =
|
|
170
|
+
v.x
|
|
171
|
+
|
|
172
|
+
y =
|
|
173
|
+
v.y
|
|
174
|
+
in
|
|
175
|
+
{ x = x * cos radians - y * sin radians
|
|
176
|
+
, y = x * sin radians + y * cos radians
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
rotateAround : Vec2 -> Float -> Vec2 -> Vec2
|
|
181
|
+
rotateAround pivot degrees p =
|
|
182
|
+
let
|
|
183
|
+
rad =
|
|
184
|
+
pi / 180.0 * degrees
|
|
185
|
+
|
|
186
|
+
translated =
|
|
187
|
+
{ x = p.x - pivot.x, y = p.y - pivot.y }
|
|
188
|
+
|
|
189
|
+
rotated =
|
|
190
|
+
{ x = translated.x * cos rad - translated.y * sin rad
|
|
191
|
+
, y = translated.x * sin rad + translated.y * cos rad
|
|
192
|
+
}
|
|
193
|
+
in
|
|
194
|
+
{ x = rotated.x + pivot.x
|
|
195
|
+
, y = rotated.y + pivot.y
|
|
196
|
+
}
|