scratchblocks-plus 1.0.0
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/LICENSE +19 -0
- package/README.md +193 -0
- package/browser.es.js +8 -0
- package/browser.js +8 -0
- package/build/scratchblocks-plus.min.es.js +12 -0
- package/build/scratchblocks-plus.min.es.js.map +1 -0
- package/build/scratchblocks-plus.min.js +12 -0
- package/build/scratchblocks-plus.min.js.map +1 -0
- package/build/translations-all-es.js +11 -0
- package/build/translations-all-es.js.map +1 -0
- package/build/translations-all.js +11 -0
- package/build/translations-all.js.map +1 -0
- package/build/translations-es.js +11 -0
- package/build/translations-es.js.map +1 -0
- package/build/translations.js +11 -0
- package/build/translations.js.map +1 -0
- package/index.d.ts +297 -0
- package/index.js +229 -0
- package/locales/ab.json +1630 -0
- package/locales/af.json +1630 -0
- package/locales/all.d.ts +108 -0
- package/locales/all.js +161 -0
- package/locales/am.json +1925 -0
- package/locales/an.json +1630 -0
- package/locales/ar.json +1924 -0
- package/locales/ast.json +1630 -0
- package/locales/az.json +1925 -0
- package/locales/be.json +1630 -0
- package/locales/bg.json +1924 -0
- package/locales/bn.json +1630 -0
- package/locales/ca.json +1930 -0
- package/locales/ckb.json +1630 -0
- package/locales/cs.json +1930 -0
- package/locales/cy.json +1929 -0
- package/locales/da.json +1924 -0
- package/locales/de.json +1929 -0
- package/locales/el.json +1931 -0
- package/locales/eo.json +1630 -0
- package/locales/es-419.json +1924 -0
- package/locales/es.json +1929 -0
- package/locales/et.json +1924 -0
- package/locales/eu.json +1924 -0
- package/locales/fa.json +1929 -0
- package/locales/fi.json +1924 -0
- package/locales/fil.json +1631 -0
- package/locales/forums.js +37 -0
- package/locales/fr.json +1929 -0
- package/locales/fy.json +1630 -0
- package/locales/ga.json +1924 -0
- package/locales/gd.json +1929 -0
- package/locales/gl.json +1924 -0
- package/locales/ha.json +1630 -0
- package/locales/he.json +1929 -0
- package/locales/hi.json +1635 -0
- package/locales/hr.json +1929 -0
- package/locales/ht.json +1630 -0
- package/locales/hu.json +1930 -0
- package/locales/hy.json +1630 -0
- package/locales/id.json +1929 -0
- package/locales/is.json +1924 -0
- package/locales/it.json +1929 -0
- package/locales/ja-Hira.json +1637 -0
- package/locales/ja.json +1931 -0
- package/locales/ka.json +1630 -0
- package/locales/kk.json +1632 -0
- package/locales/km.json +1630 -0
- package/locales/ko.json +1924 -0
- package/locales/ku.json +1632 -0
- package/locales/lt.json +1924 -0
- package/locales/lv.json +1924 -0
- package/locales/mi.json +1924 -0
- package/locales/mn.json +1631 -0
- package/locales/nb.json +1929 -0
- package/locales/nl.json +1929 -0
- package/locales/nn.json +1630 -0
- package/locales/nso.json +1630 -0
- package/locales/oc.json +1630 -0
- package/locales/or.json +1631 -0
- package/locales/pl.json +1929 -0
- package/locales/pt-br.json +1924 -0
- package/locales/pt.json +1929 -0
- package/locales/qu.json +1630 -0
- package/locales/rap.json +1632 -0
- package/locales/ro.json +1929 -0
- package/locales/ru.json +1929 -0
- package/locales/sk.json +1924 -0
- package/locales/sl.json +1929 -0
- package/locales/sr.json +1924 -0
- package/locales/sv.json +1924 -0
- package/locales/sw.json +1630 -0
- package/locales/th.json +1924 -0
- package/locales/tn.json +1630 -0
- package/locales/tr.json +1932 -0
- package/locales/uk.json +1924 -0
- package/locales/uz.json +1631 -0
- package/locales/vi.json +1925 -0
- package/locales/xh.json +1630 -0
- package/locales/zh-cn.json +1930 -0
- package/locales/zh-tw.json +1930 -0
- package/locales/zu.json +1918 -0
- package/package.json +81 -0
- package/scratch2/blocks.js +1000 -0
- package/scratch2/draw.js +452 -0
- package/scratch2/filter.js +78 -0
- package/scratch2/index.js +12 -0
- package/scratch2/style.css.js +148 -0
- package/scratch2/style.js +214 -0
- package/scratch3/blocks.js +1134 -0
- package/scratch3/draw.js +334 -0
- package/scratch3/index.js +12 -0
- package/scratch3/style.css.js +280 -0
- package/scratch3/style.js +877 -0
- package/syntax/blocks.js +921 -0
- package/syntax/commands.js +1755 -0
- package/syntax/dropdowns.js +688 -0
- package/syntax/extensions.js +34 -0
- package/syntax/index.js +17 -0
- package/syntax/model.js +566 -0
- package/syntax/syntax.js +1091 -0
package/scratch2/draw.js
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/* for constructing SVGs */
|
|
2
|
+
|
|
3
|
+
function assert(bool, message) {
|
|
4
|
+
if (!bool) {
|
|
5
|
+
throw new Error(`Assertion failed! ${message || ""}`)
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// set by SVG.init
|
|
10
|
+
let document
|
|
11
|
+
let xml
|
|
12
|
+
|
|
13
|
+
const directProps = {
|
|
14
|
+
textContent: true,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class SVG {
|
|
18
|
+
static init(window) {
|
|
19
|
+
document = window.document
|
|
20
|
+
const DOMParser = window.DOMParser
|
|
21
|
+
xml = new DOMParser().parseFromString("<xml></xml>", "application/xml")
|
|
22
|
+
SVG.XMLSerializer = window.XMLSerializer
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static makeCanvas() {
|
|
26
|
+
return document.createElement("canvas")
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static cdata(content) {
|
|
30
|
+
return xml.createCDATASection(content)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static el(name, props) {
|
|
34
|
+
const el = document.createElementNS("http://www.w3.org/2000/svg", name)
|
|
35
|
+
return SVG.setProps(el, props)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static setProps(el, props) {
|
|
39
|
+
for (const key in props) {
|
|
40
|
+
const value = String(props[key])
|
|
41
|
+
if (directProps[key]) {
|
|
42
|
+
el[key] = value
|
|
43
|
+
} else if (
|
|
44
|
+
props[key] != null &&
|
|
45
|
+
Object.prototype.hasOwnProperty.call(props, key)
|
|
46
|
+
) {
|
|
47
|
+
el.setAttributeNS(null, key, value)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return el
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static withChildren(el, children) {
|
|
54
|
+
for (const child of children) {
|
|
55
|
+
el.appendChild(child)
|
|
56
|
+
}
|
|
57
|
+
return el
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static group(children) {
|
|
61
|
+
return SVG.withChildren(SVG.el("g"), children)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static newSVG(width, height, scale) {
|
|
65
|
+
return SVG.el("svg", {
|
|
66
|
+
version: "1.1",
|
|
67
|
+
width: width * scale,
|
|
68
|
+
height: height * scale,
|
|
69
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static polygon(props) {
|
|
74
|
+
return SVG.el("polygon", { ...props, points: props.points.join(" ") })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static path(props) {
|
|
78
|
+
return SVG.el("path", { ...props, path: null, d: props.path.join(" ") })
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static text(x, y, content, props) {
|
|
82
|
+
const text = SVG.el("text", { ...props, x: x, y: y, textContent: content })
|
|
83
|
+
return text
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static symbol(href) {
|
|
87
|
+
return SVG.el("use", {
|
|
88
|
+
href: href,
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static move(dx, dy, el) {
|
|
93
|
+
SVG.setProps(el, {
|
|
94
|
+
transform: `translate(${dx} ${dy})`,
|
|
95
|
+
})
|
|
96
|
+
return el
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// translatePath takes a path string such as "M 0 0 L 0 10 L 10 0 Z", fins
|
|
100
|
+
// the individual X/Y components, and translates them by dx/dy, so as to
|
|
101
|
+
// "move" the path.
|
|
102
|
+
//
|
|
103
|
+
// This is not a particularly good way of doing this, but given we control
|
|
104
|
+
// the inputs to it it works well enough I guess?
|
|
105
|
+
static translatePath(dx, dy, path) {
|
|
106
|
+
let isX = true
|
|
107
|
+
const parts = path.split(/\s+/)
|
|
108
|
+
const out = []
|
|
109
|
+
for (let i = 0; i < parts.length; i++) {
|
|
110
|
+
let part = parts[i]
|
|
111
|
+
if (part === "A") {
|
|
112
|
+
const j = i + 5
|
|
113
|
+
out.push("A")
|
|
114
|
+
while (i < j) {
|
|
115
|
+
out.push(parts[++i])
|
|
116
|
+
}
|
|
117
|
+
continue
|
|
118
|
+
} else if (/[A-Za-z]/.test(part)) {
|
|
119
|
+
// This assertion means the path was not a valid sequence of
|
|
120
|
+
// [operation, X coordinate, Y coordinate, ...].
|
|
121
|
+
//
|
|
122
|
+
// It could indicate missing whitespace between the coordinates and the
|
|
123
|
+
// operation.
|
|
124
|
+
assert(isX, "translatePath: invalid argument")
|
|
125
|
+
} else {
|
|
126
|
+
part = +part
|
|
127
|
+
part += isX ? dx : dy
|
|
128
|
+
isX = !isX
|
|
129
|
+
}
|
|
130
|
+
out.push(part)
|
|
131
|
+
}
|
|
132
|
+
return out.join(" ")
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* shapes */
|
|
136
|
+
|
|
137
|
+
static rect(w, h, props) {
|
|
138
|
+
return SVG.el("rect", { ...props, x: 0, y: 0, width: w, height: h })
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static ellipse(w, h, props) {
|
|
142
|
+
return SVG.el("ellipse", {
|
|
143
|
+
...props,
|
|
144
|
+
cx: w / 2,
|
|
145
|
+
cy: h / 2,
|
|
146
|
+
rx: w / 2,
|
|
147
|
+
ry: h / 2,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static arc(p1x, p1y, p2x, p2y, rx, ry) {
|
|
152
|
+
return `L ${p1x} ${p1y} A ${rx} ${ry} 0 0 1 ${p2x} ${p2y}`
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static arcw(p1x, p1y, p2x, p2y, rx, ry) {
|
|
156
|
+
return `L ${p1x} ${p1y} A ${rx} ${ry} 0 0 0 ${p2x} ${p2y}`
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static roundedPath(w, h) {
|
|
160
|
+
const r = h / 2
|
|
161
|
+
return [
|
|
162
|
+
"M",
|
|
163
|
+
r,
|
|
164
|
+
0,
|
|
165
|
+
SVG.arc(w - r, 0, w - r, h, r, r),
|
|
166
|
+
SVG.arc(r, h, r, 0, r, r),
|
|
167
|
+
"Z",
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static roundedRect(w, h, props) {
|
|
172
|
+
return SVG.path({ ...props, path: SVG.roundedPath(w, h) })
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static pointedPath(w, h) {
|
|
176
|
+
const r = h / 2
|
|
177
|
+
return [
|
|
178
|
+
"M",
|
|
179
|
+
r,
|
|
180
|
+
0,
|
|
181
|
+
"L",
|
|
182
|
+
w - r,
|
|
183
|
+
0,
|
|
184
|
+
w,
|
|
185
|
+
r,
|
|
186
|
+
"L",
|
|
187
|
+
w,
|
|
188
|
+
r,
|
|
189
|
+
w - r,
|
|
190
|
+
h,
|
|
191
|
+
"L",
|
|
192
|
+
r,
|
|
193
|
+
h,
|
|
194
|
+
0,
|
|
195
|
+
r,
|
|
196
|
+
"L",
|
|
197
|
+
0,
|
|
198
|
+
r,
|
|
199
|
+
r,
|
|
200
|
+
0,
|
|
201
|
+
"Z",
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static pointedRect(w, h, props) {
|
|
206
|
+
return SVG.path({ ...props, path: SVG.pointedPath(w, h) })
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static getTop(w) {
|
|
210
|
+
return `M 0 3
|
|
211
|
+
L 3 0
|
|
212
|
+
L 13 0
|
|
213
|
+
L 16 3
|
|
214
|
+
L 24 3
|
|
215
|
+
L 27 0
|
|
216
|
+
L ${w - 3} 0
|
|
217
|
+
L ${w} 3`
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static getRingTop(w) {
|
|
221
|
+
return `M 0 3
|
|
222
|
+
L 3 0
|
|
223
|
+
L 7 0
|
|
224
|
+
L 10 3
|
|
225
|
+
L 16 3
|
|
226
|
+
L 19 0
|
|
227
|
+
L ${w - 3} 0
|
|
228
|
+
L ${w} 3`
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static getRightAndBottom(w, y, hasNotch, inset) {
|
|
232
|
+
if (typeof inset === "undefined") {
|
|
233
|
+
inset = 0
|
|
234
|
+
}
|
|
235
|
+
let arr = ["L", w, y - 3, "L", w - 3, y]
|
|
236
|
+
if (hasNotch) {
|
|
237
|
+
arr = arr.concat([
|
|
238
|
+
"L",
|
|
239
|
+
inset + 27,
|
|
240
|
+
y,
|
|
241
|
+
"L",
|
|
242
|
+
inset + 24,
|
|
243
|
+
y + 3,
|
|
244
|
+
"L",
|
|
245
|
+
inset + 16,
|
|
246
|
+
y + 3,
|
|
247
|
+
"L",
|
|
248
|
+
inset + 13,
|
|
249
|
+
y,
|
|
250
|
+
])
|
|
251
|
+
}
|
|
252
|
+
if (inset > 0) {
|
|
253
|
+
arr = arr.concat(["L", inset + 2, y, "L", inset, y + 2])
|
|
254
|
+
} else {
|
|
255
|
+
arr = arr.concat(["L", inset + 3, y, "L", 0, y - 3])
|
|
256
|
+
}
|
|
257
|
+
return arr.join(" ")
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static getArm(w, armTop) {
|
|
261
|
+
return `L 15 ${armTop - 2}
|
|
262
|
+
L 17 ${armTop}
|
|
263
|
+
L ${w - 3} ${armTop}
|
|
264
|
+
L ${w} ${armTop + 3}`
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static stackRect(w, h, props) {
|
|
268
|
+
return SVG.path({
|
|
269
|
+
...props,
|
|
270
|
+
path: [SVG.getTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"],
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
static capPath(w, h) {
|
|
275
|
+
return [SVG.getTop(w), SVG.getRightAndBottom(w, h, false, 0), "Z"]
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
static capRect(w, h, props) {
|
|
279
|
+
return SVG.path({ ...props, path: SVG.capPath(w, h) })
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
static hatRect(w, h, props) {
|
|
283
|
+
return SVG.path({
|
|
284
|
+
...props,
|
|
285
|
+
path: [
|
|
286
|
+
"M",
|
|
287
|
+
0,
|
|
288
|
+
12,
|
|
289
|
+
SVG.arc(0, 12, 80, 10, 80, 80),
|
|
290
|
+
"L",
|
|
291
|
+
w - 3,
|
|
292
|
+
10,
|
|
293
|
+
"L",
|
|
294
|
+
w,
|
|
295
|
+
10 + 3,
|
|
296
|
+
SVG.getRightAndBottom(w, h, true),
|
|
297
|
+
"Z",
|
|
298
|
+
],
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
static curve(p1x, p1y, p2x, p2y, roundness) {
|
|
303
|
+
roundness = roundness || 0.42
|
|
304
|
+
const midX = (p1x + p2x) / 2.0
|
|
305
|
+
const midY = (p1y + p2y) / 2.0
|
|
306
|
+
const cx = Math.round(midX + roundness * (p2y - p1y))
|
|
307
|
+
const cy = Math.round(midY - roundness * (p2x - p1x))
|
|
308
|
+
return `${cx} ${cy} ${p2x} ${p2y}`
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static procHatBase(w, h, archRoundness, props) {
|
|
312
|
+
// TODO use arc()
|
|
313
|
+
archRoundness = Math.min(0.2, 35 / w)
|
|
314
|
+
return SVG.path({
|
|
315
|
+
...props,
|
|
316
|
+
path: [
|
|
317
|
+
"M",
|
|
318
|
+
0,
|
|
319
|
+
15,
|
|
320
|
+
"Q",
|
|
321
|
+
SVG.curve(0, 15, w, 15, archRoundness),
|
|
322
|
+
SVG.getRightAndBottom(w, h, true),
|
|
323
|
+
"M",
|
|
324
|
+
-1,
|
|
325
|
+
13,
|
|
326
|
+
"Q",
|
|
327
|
+
SVG.curve(-1, 13, w + 1, 13, archRoundness),
|
|
328
|
+
"Q",
|
|
329
|
+
SVG.curve(w + 1, 13, w, 16, 0.6),
|
|
330
|
+
"Q",
|
|
331
|
+
SVG.curve(w, 16, 0, 16, -archRoundness),
|
|
332
|
+
"Q",
|
|
333
|
+
SVG.curve(0, 16, -1, 13, 0.6),
|
|
334
|
+
"Z",
|
|
335
|
+
],
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
static procHatCap(w, h, archRoundness) {
|
|
340
|
+
// TODO use arc()
|
|
341
|
+
// TODO this doesn't look quite right
|
|
342
|
+
return SVG.path({
|
|
343
|
+
path: [
|
|
344
|
+
"M",
|
|
345
|
+
-1,
|
|
346
|
+
13,
|
|
347
|
+
"Q",
|
|
348
|
+
SVG.curve(-1, 13, w + 1, 13, archRoundness),
|
|
349
|
+
"Q",
|
|
350
|
+
SVG.curve(w + 1, 13, w, 16, 0.6),
|
|
351
|
+
"Q",
|
|
352
|
+
SVG.curve(w, 16, 0, 16, -archRoundness),
|
|
353
|
+
"Q",
|
|
354
|
+
SVG.curve(0, 16, -1, 13, 0.6),
|
|
355
|
+
"Z",
|
|
356
|
+
],
|
|
357
|
+
class: "sb-define-hat-cap",
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
static procHatRect(w, h, props) {
|
|
362
|
+
const q = 52
|
|
363
|
+
const y = h - q
|
|
364
|
+
|
|
365
|
+
const archRoundness = Math.min(0.2, 35 / w)
|
|
366
|
+
|
|
367
|
+
return SVG.move(
|
|
368
|
+
0,
|
|
369
|
+
y,
|
|
370
|
+
SVG.group([
|
|
371
|
+
SVG.procHatBase(w, q, archRoundness, props),
|
|
372
|
+
SVG.procHatCap(w, q, archRoundness),
|
|
373
|
+
]),
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
static mouthRect(w, h, isFinal, lines, props) {
|
|
378
|
+
let y = lines[0].height
|
|
379
|
+
const p = [SVG.getTop(w), SVG.getRightAndBottom(w, y, true, 15)]
|
|
380
|
+
for (let i = 1; i < lines.length; i += 2) {
|
|
381
|
+
const isLast = i + 2 === lines.length
|
|
382
|
+
|
|
383
|
+
y += lines[i].height - 3
|
|
384
|
+
p.push(SVG.getArm(w, y))
|
|
385
|
+
|
|
386
|
+
const hasNotch = !(isLast && isFinal)
|
|
387
|
+
const inset = isLast ? 0 : 15
|
|
388
|
+
y += lines[i + 1].height + 3
|
|
389
|
+
p.push(SVG.getRightAndBottom(w, y, hasNotch, inset))
|
|
390
|
+
}
|
|
391
|
+
return SVG.path({ ...props, path: p })
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
static ringRect(w, h, cy, cw, ch, shape, props) {
|
|
395
|
+
const r = 8
|
|
396
|
+
const func =
|
|
397
|
+
shape === "reporter"
|
|
398
|
+
? SVG.roundedPath
|
|
399
|
+
: shape === "boolean"
|
|
400
|
+
? SVG.pointedPath
|
|
401
|
+
: SVG.capPath
|
|
402
|
+
return SVG.path({
|
|
403
|
+
...props,
|
|
404
|
+
path: [
|
|
405
|
+
"M",
|
|
406
|
+
r,
|
|
407
|
+
0,
|
|
408
|
+
SVG.arcw(r, 0, 0, r, r, r),
|
|
409
|
+
SVG.arcw(0, h - r, r, h, r, r),
|
|
410
|
+
SVG.arcw(w - r, h, w, h - r, r, r),
|
|
411
|
+
SVG.arcw(w, r, w - r, 0, r, r),
|
|
412
|
+
"Z",
|
|
413
|
+
SVG.translatePath(4, cy || 4, func(cw, ch).join(" ")),
|
|
414
|
+
],
|
|
415
|
+
"fill-rule": "even-odd",
|
|
416
|
+
})
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
static commentRect(w, h, props) {
|
|
420
|
+
const r = 6
|
|
421
|
+
return SVG.path({
|
|
422
|
+
...props,
|
|
423
|
+
class: "sb-comment",
|
|
424
|
+
path: [
|
|
425
|
+
"M",
|
|
426
|
+
r,
|
|
427
|
+
0,
|
|
428
|
+
SVG.arc(w - r, 0, w, r, r, r),
|
|
429
|
+
SVG.arc(w, h - r, w - r, h, r, r),
|
|
430
|
+
SVG.arc(r, h, 0, h - r, r, r),
|
|
431
|
+
SVG.arc(0, r, r, 0, r, r),
|
|
432
|
+
"Z",
|
|
433
|
+
],
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
static commentLine(width, props) {
|
|
438
|
+
return SVG.move(
|
|
439
|
+
-width,
|
|
440
|
+
9,
|
|
441
|
+
SVG.rect(width, 2, { ...props, class: "sb-comment-line" }),
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
static strikethroughLine(w, props) {
|
|
446
|
+
return SVG.path({
|
|
447
|
+
...props,
|
|
448
|
+
path: ["M", 0, 0, "L", w, 0],
|
|
449
|
+
class: "sb-diff sb-diff-del",
|
|
450
|
+
})
|
|
451
|
+
}
|
|
452
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import SVG from "./draw.js"
|
|
2
|
+
|
|
3
|
+
export default class Filter {
|
|
4
|
+
constructor(id, props) {
|
|
5
|
+
this.el = SVG.el("filter", {
|
|
6
|
+
...props,
|
|
7
|
+
id: id,
|
|
8
|
+
x0: "-50%",
|
|
9
|
+
y0: "-50%",
|
|
10
|
+
width: "200%",
|
|
11
|
+
height: "200%",
|
|
12
|
+
})
|
|
13
|
+
this.highestId = 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fe(name, props, children) {
|
|
17
|
+
const shortName = name.toLowerCase().replace(/gaussian|osite/, "")
|
|
18
|
+
const id = `${shortName}-${++this.highestId}`
|
|
19
|
+
this.el.appendChild(
|
|
20
|
+
SVG.withChildren(
|
|
21
|
+
SVG.el(`fe${name}`, { ...props, result: id }),
|
|
22
|
+
children || [],
|
|
23
|
+
),
|
|
24
|
+
)
|
|
25
|
+
return id
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
comp(op, in1, in2, props) {
|
|
29
|
+
return this.fe("Composite", { ...props, operator: op, in: in1, in2: in2 })
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
subtract(in1, in2) {
|
|
33
|
+
return this.comp("arithmetic", in1, in2, { k2: +1, k3: -1 })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
offset(dx, dy, in1) {
|
|
37
|
+
return this.fe("Offset", {
|
|
38
|
+
in: in1,
|
|
39
|
+
dx: dx,
|
|
40
|
+
dy: dy,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
flood(color, opacity, in1) {
|
|
45
|
+
return this.fe("Flood", {
|
|
46
|
+
in: in1,
|
|
47
|
+
"flood-color": color,
|
|
48
|
+
"flood-opacity": opacity,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
blur(dev, in1) {
|
|
53
|
+
return this.fe("GaussianBlur", {
|
|
54
|
+
in: in1,
|
|
55
|
+
stdDeviation: `${dev} ${dev}`,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
colorMatrix(in1, values) {
|
|
60
|
+
return this.fe("ColorMatrix", {
|
|
61
|
+
in: in1,
|
|
62
|
+
type: "matrix",
|
|
63
|
+
values: values.join(" "),
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
merge(children) {
|
|
68
|
+
this.fe(
|
|
69
|
+
"Merge",
|
|
70
|
+
{},
|
|
71
|
+
children.map(name =>
|
|
72
|
+
SVG.el("feMergeNode", {
|
|
73
|
+
in: name,
|
|
74
|
+
}),
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import SVG from "./draw.js"
|
|
2
|
+
import { LabelView } from "./blocks.js"
|
|
3
|
+
import style from "./style.js"
|
|
4
|
+
|
|
5
|
+
export function init(window) {
|
|
6
|
+
SVG.init(window)
|
|
7
|
+
|
|
8
|
+
LabelView.measuring = SVG.makeCanvas().getContext("2d")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const makeStyle = style.makeStyle
|
|
12
|
+
export { newView } from "./blocks.js"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Processed by Rollup
|
|
2
|
+
export default `
|
|
3
|
+
.sb-label {
|
|
4
|
+
font-family: Lucida Grande, Verdana, Arial, DejaVu Sans, sans-serif;
|
|
5
|
+
font-weight: bold;
|
|
6
|
+
fill: #fff;
|
|
7
|
+
font-size: 10px;
|
|
8
|
+
word-spacing: +1px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.sb-obsolete {
|
|
12
|
+
fill: #d42828;
|
|
13
|
+
}
|
|
14
|
+
.sb-motion {
|
|
15
|
+
fill: #4a6cd4;
|
|
16
|
+
}
|
|
17
|
+
.sb-looks {
|
|
18
|
+
fill: #8a55d7;
|
|
19
|
+
}
|
|
20
|
+
.sb-sound {
|
|
21
|
+
fill: #bb42c3;
|
|
22
|
+
}
|
|
23
|
+
.sb-pen {
|
|
24
|
+
fill: #0e9a6c;
|
|
25
|
+
}
|
|
26
|
+
.sb-events {
|
|
27
|
+
fill: #c88330;
|
|
28
|
+
}
|
|
29
|
+
.sb-control {
|
|
30
|
+
fill: #e1a91a;
|
|
31
|
+
}
|
|
32
|
+
.sb-sensing {
|
|
33
|
+
fill: #2ca5e2;
|
|
34
|
+
}
|
|
35
|
+
.sb-operators {
|
|
36
|
+
fill: #5cb712;
|
|
37
|
+
}
|
|
38
|
+
.sb-variables {
|
|
39
|
+
fill: #ee7d16;
|
|
40
|
+
}
|
|
41
|
+
.sb-list {
|
|
42
|
+
fill: #cc5b22;
|
|
43
|
+
}
|
|
44
|
+
.sb-custom {
|
|
45
|
+
fill: #632d99;
|
|
46
|
+
}
|
|
47
|
+
.sb-custom-arg {
|
|
48
|
+
fill: #5947b1;
|
|
49
|
+
}
|
|
50
|
+
.sb-extension {
|
|
51
|
+
fill: #4b4a60;
|
|
52
|
+
}
|
|
53
|
+
.sb-grey {
|
|
54
|
+
fill: #969696;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.sb-bevel {
|
|
58
|
+
filter: url(#bevelFilter);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sb-input {
|
|
62
|
+
filter: url(#inputBevelFilter);
|
|
63
|
+
}
|
|
64
|
+
.sb-input-number,
|
|
65
|
+
.sb-input-string,
|
|
66
|
+
.sb-input-number-dropdown {
|
|
67
|
+
fill: #fff;
|
|
68
|
+
}
|
|
69
|
+
.sb-literal-number,
|
|
70
|
+
.sb-literal-string,
|
|
71
|
+
.sb-literal-number-dropdown,
|
|
72
|
+
.sb-literal-dropdown {
|
|
73
|
+
font-weight: normal;
|
|
74
|
+
font-size: 9px;
|
|
75
|
+
word-spacing: 0;
|
|
76
|
+
}
|
|
77
|
+
.sb-literal-number,
|
|
78
|
+
.sb-literal-string,
|
|
79
|
+
.sb-literal-number-dropdown {
|
|
80
|
+
fill: #000;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.sb-darker {
|
|
84
|
+
filter: url(#inputDarkFilter);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.sb-outline {
|
|
88
|
+
stroke: #fff;
|
|
89
|
+
stroke-opacity: 0.2;
|
|
90
|
+
stroke-width: 2;
|
|
91
|
+
fill: none;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.sb-define-hat-cap {
|
|
95
|
+
stroke: #632d99;
|
|
96
|
+
stroke-width: 1;
|
|
97
|
+
fill: #8e2ec2;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.sb-comment {
|
|
101
|
+
fill: #ffffa5;
|
|
102
|
+
stroke: #d0d1d2;
|
|
103
|
+
stroke-width: 1;
|
|
104
|
+
}
|
|
105
|
+
.sb-comment-line {
|
|
106
|
+
fill: #ffff80;
|
|
107
|
+
}
|
|
108
|
+
.sb-comment-label {
|
|
109
|
+
font-family: Helvetica, Arial, DejaVu Sans, sans-serif;
|
|
110
|
+
font-weight: bold;
|
|
111
|
+
fill: #5c5d5f;
|
|
112
|
+
word-spacing: 0;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.sb-diff {
|
|
117
|
+
fill: none;
|
|
118
|
+
stroke: #000;
|
|
119
|
+
}
|
|
120
|
+
.sb-diff-ins {
|
|
121
|
+
stroke-width: 2px;
|
|
122
|
+
}
|
|
123
|
+
.sb-diff-del {
|
|
124
|
+
stroke-width: 3px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Block highlight styles */
|
|
128
|
+
.sb-highlight:not(.sb-blink) {
|
|
129
|
+
fill: #FBF883 !important;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Blinking animation for jump-to-block */
|
|
133
|
+
.sb-blink {
|
|
134
|
+
animation: sb-blink-animation 0.5s 3;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@keyframes sb-blink-animation {
|
|
138
|
+
0% {
|
|
139
|
+
fill: #FBF883;
|
|
140
|
+
}
|
|
141
|
+
50% {
|
|
142
|
+
fill: #FBF883;
|
|
143
|
+
animation-timing-function: step-start;
|
|
144
|
+
}
|
|
145
|
+
100% {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
`
|