-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-- Copyright 2026 Shota FUJI
--
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
--
-- SPDX-License-Identifier: MPL-2.0
module Template exposing (template)
import Length exposing (toMM)
import Parameters exposing (Parameters, canvasSizeDimension)
import String
import Svg exposing (..)
import Svg.Attributes exposing (..)
import Svg.Path exposing (LargeArcFlag(..), PathCommand(..), PointMode(..), SweepFlag(..))
type Anchor
= TopLeft ( Int, Int )
| TopRight ( Int, Int )
| BottomLeft ( Int, Int )
| BottomRight ( Int, Int )
topLeftFor : Anchor -> ( Int, Int ) -> ( Int, Int )
topLeftFor anchor ( width, height ) =
case anchor of
TopLeft ( x, y ) ->
( x, y )
TopRight ( x, y ) ->
( x - width, y )
BottomLeft ( x, y ) ->
( x, y - height )
BottomRight ( x, y ) ->
( x - width, y - height )
template : Parameters -> List (Svg.Attribute msg) -> Svg.Svg msg
template params attrs =
let
( canvasWidth, canvasHeight ) =
canvasSizeDimension params.canvasSize
|> Tuple.mapBoth toMM toMM
|> Tuple.mapBoth ceiling ceiling
in
svg
(viewBox (String.join " " [ "0", "0", String.fromInt canvasWidth, String.fromInt canvasHeight ])
:: class "print"
:: attrs
)
-- TODO: Make margin configurable
[ scaleChecker (BottomLeft ( 10, canvasHeight - 10 ))
, longPiece params (TopLeft ( 10, 10 ))
, shortPiece params (TopLeft ( ceiling (toMM params.lugWidth) + 20, 10 ))
]
scaleChecker : Anchor -> Svg msg
scaleChecker anchor =
let
( ox, oy ) =
topLeftFor anchor ( 10, 10 )
px : Int -> String
px n =
String.fromInt (ox + n)
py : Int -> String
py n =
String.fromInt (oy + n)
in
g
[]
[ g
[ stroke "currentColor", strokeWidth "0.2" ]
[ line
[ x1 (px 0), y1 (py 8), x2 (px 0), y2 (py 10) ]
[]
, line
[ x1 (px 0), y1 (py 9), x2 (px 10), y2 (py 9) ]
[]
, line
[ x1 (px 10), y1 (py 8), x2 (px 10), y2 (py 10) ]
[]
]
, text_
[ x (px 5)
, y (py 7)
, fontSize "3"
, fontWeight "100"
, textAnchor "middle"
, fill "currentColor"
]
[ text "10mm" ]
]
longPiece : Parameters -> Anchor -> Svg msg
longPiece params anchor =
let
lugWidth =
toMM params.lugWidth
length =
toMM params.longPiece.length
( ox, oy ) =
topLeftFor anchor ( ceiling lugWidth, ceiling length )
in
g
[]
[ g
[ fill "none", stroke "currentColor", strokeWidth "0.3" ]
[ Svg.path
[ Svg.Path.d
[ MoveTo Absolute ( toFloat ox, toFloat oy )
, VerticalLineTo Relative (length - lugWidth)
, EllipticalArcCurve Relative
{ rx = lugWidth / 2
, ry = lugWidth / 2
, angle = 0.0
, largeArcFlag = LargeArc
, sweepFlag = Counterclockwise
, x = lugWidth
, y = 0
}
[]
, VerticalLineTo Relative -(length - lugWidth)
, ClosePath
]
]
[]
]
]
shortPiece : Parameters -> Anchor -> Svg msg
shortPiece params anchor =
let
lugWidth =
toMM params.lugWidth
length =
toMM params.shortPiece.length
( ox, oy ) =
topLeftFor anchor ( ceiling lugWidth, ceiling length )
in
g
[]
[ g
[ fill "none", stroke "currentColor", strokeWidth "0.3" ]
[ Svg.path
[ Svg.Path.d
[ MoveTo Absolute ( toFloat ox, toFloat oy )
, VerticalLineTo Relative length
, HorizontalLineTo Relative lugWidth
, VerticalLineTo Relative -length
, ClosePath
]
]
[]
]
]