@labcat2020/p5.audioreactive 0.1.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.
@@ -0,0 +1,944 @@
1
+ // p5.Pattern
2
+ // MIT License
3
+ // Copyright (c) 2021 Taichi Sayama
4
+ // A pattern drawing library for p5.js.
5
+ import * as p5 from "p5";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // PatternControler Calss
9
+ // ---------------------------------------------------------------------------
10
+
11
+ function PatternControler()
12
+ {
13
+ this.x = 0;
14
+ this.y = 0;
15
+ this.w = 0;
16
+ this.h = 0;
17
+ this.colors = ['#FFFFFF', '#000000'];
18
+ this.angle = 0;
19
+ this.patternFunction = null;
20
+ this.renderTarget = null;
21
+ }
22
+
23
+ // ---------------------------------------------------------------------------
24
+
25
+ /*
26
+ Function to change the amount of pattern rotation.
27
+ Use patternAngle() to check current angle.
28
+ */
29
+ PatternControler.prototype.patternAngle = function(_angle)
30
+ {
31
+ if(typeof(_angle) === 'number') this.angle = _angle;
32
+ return this.angle;
33
+ }
34
+
35
+
36
+ /*
37
+ Function to set the drawing function.
38
+ */
39
+ PatternControler.prototype.setPatternFunction = function(_func)
40
+ {
41
+ if(typeof(_func) !== 'function')return false;
42
+ this.patternFunction = _func;
43
+ return this.patternFunction;
44
+ };
45
+
46
+
47
+ /**
48
+ * Function to set parameters and draw pattern.
49
+ * @param {Number} _x x-coordinate of the corner of pattern
50
+ * @param {Number} _y y-coordinate of the corner of pattern
51
+ * @param {Number} _w width of the pattern
52
+ * @param {Number} _h height of the pattern
53
+ * @param {} _renderTarget
54
+ */
55
+ PatternControler.prototype.applyPattern = function(_x, _y, _w, _h, _renderTarget)
56
+ {
57
+ this._setPatternArea(_x, _y, _w, _h);
58
+ this._setRenderTarget(_renderTarget);
59
+ this.renderTarget = _renderTarget;
60
+ this._drawPattern();
61
+ }
62
+
63
+ /**
64
+ * Function to set the color palette of the pattern.
65
+ * Use patternColors() to check current palette.
66
+ * @param {Array} _colsArr
67
+ */
68
+ PatternControler.prototype.patternColors = function(_colsArr)
69
+ {
70
+ if(Array.isArray(_colsArr))this.colors = _colsArr;
71
+ //return this.colors;
72
+ return this.colors.slice(0, this.colors.length);
73
+ }
74
+
75
+
76
+
77
+ // ---------------------------------------------------------------------------
78
+ //Private functions
79
+
80
+ /*
81
+ Function to change the drawing range of a pattern
82
+ */
83
+ PatternControler.prototype._setPatternArea = function(_x, _y, _w, _h)
84
+ {
85
+ this.x = _x;
86
+ this.y = _y;
87
+ this.w = _w;
88
+ this.h = _h;
89
+ };
90
+
91
+ /*
92
+ Function to set the pattern target.
93
+ */
94
+ PatternControler.prototype._setRenderTarget = function(_renderTarget)
95
+ {
96
+ this.renderTarget = _renderTarget;
97
+ };
98
+
99
+ /*
100
+ Function to draw the pattern.
101
+ */
102
+ PatternControler.prototype._drawPattern = function()
103
+ {
104
+ const rt = this.renderTarget;
105
+
106
+ //Generate a drawing function. apply rotation
107
+ const func = typeof(this.patternFunction) === 'function' ?
108
+ this.patternFunction : this._flatFill();
109
+
110
+ const rotatedFunc = this._rotatedFuncGen(func, this.angle);
111
+
112
+ //cache renderMode
113
+ const pRectMode = rt._renderer._rectMode;
114
+ const pEllipseMode = rt._renderer._ellipseMode;
115
+
116
+ //draw
117
+ rt.push();
118
+ rt.drawingContext.clip();
119
+ rt.translate(this.x, this.y);
120
+ rotatedFunc(this.w, this.h, rt);
121
+ rt.pop();
122
+
123
+ //reset renderMode
124
+ rt.rectMode(pRectMode);
125
+ rt.ellipseMode(pEllipseMode);
126
+ };
127
+
128
+ /*
129
+ Generate a drawing function with rotation applied.
130
+ */
131
+ PatternControler.prototype._rotatedFuncGen = function(_ptnFunc, _angle)
132
+ {
133
+ const func = function(_w, _h, _rt)
134
+ {
135
+ //Calculate the new size according to the rotation angle.
136
+ const p1 = _rt.createVector(-_w/2, _h/2).rotate(_angle);
137
+ const p2 = _rt.createVector(_w/2, _h/2).rotate(_angle);
138
+ const nw = Math.max(Math.abs(p1.x), Math.abs(p2.x)) * 2;
139
+ const nh = Math.max(Math.abs(p1.y), Math.abs(p2.y)) * 2;
140
+
141
+ _rt.push();
142
+ _rt.translate(_w / 2, _h / 2);
143
+ _rt.rotate(_angle);
144
+ _rt.translate(-nw / 2, -nh / 2);
145
+ _ptnFunc(nw, nh, _rt);
146
+ _rt.pop();
147
+ }
148
+
149
+ return func;
150
+ };
151
+
152
+ /*
153
+ Default pattern function.
154
+ */
155
+ PatternControler.prototype._flatFill = function()
156
+ {
157
+ const c = this.patternColors();
158
+
159
+ return function(_w, _h, _rt)
160
+ {
161
+ _rt.rectMode(_rt.CORNER);
162
+ _rt.fill(c[0]);
163
+ _rt.noStroke();
164
+ _rt.rect(0, 0, _w, _h);
165
+ }
166
+ };
167
+
168
+
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // Vertex Infomation Class
172
+ // ---------------------------------------------------------------------------
173
+
174
+ function PatternVertexInfo()
175
+ {
176
+ this.verticies = [];
177
+ this.isCurve = false;
178
+ this.curveAreaMult = 1.25;
179
+ }
180
+
181
+ // ---------------------------------------------------------------------------
182
+
183
+ PatternVertexInfo.prototype.reset = function()
184
+ {
185
+ this.verticies = [];
186
+ this.isCurve = false;
187
+ };
188
+
189
+ PatternVertexInfo.prototype.addVertex = function(x, y)
190
+ {
191
+ this.verticies.push([x, y]);
192
+ };
193
+
194
+ PatternVertexInfo.prototype.addCurveVertex = function(x, y)
195
+ {
196
+ this.addVertex(x, y);
197
+ this.isCurve = true;
198
+ };
199
+
200
+ PatternVertexInfo.prototype.addBezierVertex = function(x2, y2, x3, y3, x4, y4)
201
+ {
202
+ this.addVertex(x2, y2);
203
+ this.addVertex(x3, y3);
204
+ this.addVertex(x4, y4);
205
+ };
206
+
207
+ PatternVertexInfo.prototype.addQuadraticVertex = function(cx, cy, x3, y3)
208
+ {
209
+ this.addVertex(cx, cy);
210
+ this.addVertex(x3, y3);
211
+ };
212
+
213
+ PatternVertexInfo.prototype.culclateArea = function()
214
+ {
215
+ let minx = this.verticies[0][0];
216
+ let maxx = minx;
217
+ let miny = this.verticies[0][1];
218
+ let maxy = miny;
219
+
220
+ for(let i = 0; i < this.verticies.length; i++)
221
+ {
222
+ let nx = this.verticies[i][0];
223
+ let ny = this.verticies[i][1];
224
+
225
+ minx = Math.min(minx, nx);
226
+ maxx = Math.max(maxx, nx);
227
+ miny = Math.min(miny, ny);
228
+ maxy = Math.max(maxy, ny);
229
+ }
230
+
231
+ let w = maxx - minx;
232
+ let h = maxy - miny;
233
+ let cx = w / 2 + minx;
234
+ let cy = h / 2 + miny;
235
+
236
+ if(this.isCurve)
237
+ {
238
+ w *= this.curveAreaMult;
239
+ h *= this.curveAreaMult;
240
+ }
241
+
242
+ let x = cx - w /2;
243
+ let y = cy - h /2;
244
+
245
+ const area = {x : x, y : y, w : w, h : h};
246
+
247
+ return area;
248
+ };
249
+
250
+
251
+
252
+ // ---------------------------------------------------------------------------
253
+ // p5 extentions
254
+ // ---------------------------------------------------------------------------
255
+
256
+
257
+ p5.prototype._patternControler = new PatternControler();
258
+ p5.Graphics.prototype._patternControler = new PatternControler();
259
+
260
+ p5.prototype._patternVertexInfo = new PatternVertexInfo();
261
+ p5.Graphics.prototype._patternVertexInfo = new PatternVertexInfo();
262
+
263
+
264
+ /**
265
+ * Function to change the amount of pattern rotation.
266
+ * Use patternAngle() to check current angle.
267
+ * @param {Number} _angle the angle of rotation,
268
+ * specified in radians or degrees, depending on current angleMode
269
+ */
270
+ p5.prototype.patternAngle = function(_angle)
271
+ {
272
+ return this._patternControler.patternAngle(_angle);
273
+ };
274
+
275
+
276
+ /**
277
+ * Function to set the color palette of the pattern.
278
+ * Use patternColors() to check current palette.
279
+ * @param {Array} _colsArr
280
+ */
281
+ p5.prototype.patternColors = function(_colsArr)
282
+ {
283
+ return this._patternControler.patternColors(_colsArr);
284
+ };
285
+
286
+
287
+ /**
288
+ * Function to set the pattern
289
+ * @param {function} _func Pattern drawing function.
290
+ */
291
+ p5.prototype.pattern = function(_func)
292
+ {
293
+ return this._patternControler.setPatternFunction(_func);
294
+ };
295
+
296
+
297
+ // ---------------------------------------------------------------------------
298
+ //Shape functions
299
+
300
+ (function()
301
+ {
302
+ /*
303
+ Functions to adjust coordinate data
304
+ */
305
+ const _modeAdjust = function(a, b, c, d, mode)
306
+ {
307
+ if (mode === p5.prototype.CORNER) {
308
+ return { x: a, y: b, w: c, h: d };
309
+ } else if (mode === p5.prototype.CORNERS) {
310
+ return { x: a, y: b, w: c - a, h: d - b };
311
+ } else if (mode === p5.prototype.RADIUS) {
312
+ return { x: a - c, y: b - d, w: 2 * c, h: 2 * d };
313
+ } else if (mode === p5.prototype.CENTER) {
314
+ return { x: a - c * 0.5, y: b - d * 0.5, w: c, h: d };
315
+ }
316
+ };
317
+
318
+ /*
319
+ Function to disable drawing of fills and stroke.
320
+ */
321
+ const _disableColor = function(_renderTarget)
322
+ {
323
+ _renderTarget.noStroke();
324
+ _renderTarget.fill(255, 0);
325
+ };
326
+
327
+
328
+ // ---------------------------------------------------------------------------
329
+
330
+ //rect
331
+ p5.prototype.rectPattern = function(...args)
332
+ {
333
+ _disableColor(this);
334
+ const r = this.rect(...args);
335
+
336
+ const val = _modeAdjust(
337
+ arguments[0],
338
+ arguments[1],
339
+ arguments[2],
340
+ arguments[3],
341
+ this._renderer._rectMode
342
+ );
343
+
344
+ this._patternControler.applyPattern(val.x, val.y, val.w, val.h, this);
345
+
346
+ return r;
347
+ };
348
+
349
+ //square
350
+ p5.prototype.squarePattern = function(...args)
351
+ {
352
+ _disableColor(this);
353
+ const r = this.square(...args);
354
+
355
+ const val = _modeAdjust(
356
+ arguments[0],
357
+ arguments[1],
358
+ arguments[2],
359
+ arguments[2],
360
+ this._renderer._rectMode
361
+ );
362
+
363
+ this._patternControler.applyPattern(val.x, val.y, val.w, val.h, this);
364
+ return r;
365
+ };
366
+
367
+ //ellipse
368
+ p5.prototype.ellipsePattern = function(...args)
369
+ {
370
+ _disableColor(this);
371
+ const r = this.ellipse(...args);
372
+
373
+ const val = _modeAdjust(
374
+ arguments[0],
375
+ arguments[1],
376
+ arguments[2],
377
+ arguments[3],
378
+ this._renderer._ellipseMode
379
+ );
380
+
381
+ this._patternControler.applyPattern(val.x, val.y, val.w, val.h, this);
382
+ return r;
383
+ };
384
+
385
+
386
+ //arc
387
+ p5.prototype.arcPattern = function(...args)
388
+ {
389
+ _disableColor(this);
390
+ const r = this.arc(...args);
391
+
392
+ const val = _modeAdjust(
393
+ arguments[0],
394
+ arguments[1],
395
+ arguments[2],
396
+ arguments[3],
397
+ this._renderer._ellipseMode
398
+ );
399
+
400
+ this._patternControler.applyPattern(val.x, val.y, val.w, val.h, this);
401
+ return r;
402
+ };
403
+
404
+
405
+ //circle
406
+ p5.prototype.circlePattern = function(...args)
407
+ {
408
+ _disableColor(this);
409
+ const r = this.circle(...args);
410
+
411
+ const val = _modeAdjust(
412
+ arguments[0],
413
+ arguments[1],
414
+ arguments[2],
415
+ arguments[2],
416
+ this._renderer._ellipseMode
417
+ );
418
+ this._patternControler.applyPattern(val.x, val.y, val.w, val.h, this);
419
+ return r;
420
+ };
421
+
422
+
423
+ //triangle
424
+ p5.prototype.trianglePattern = function(...args)
425
+ {
426
+ _disableColor(this);
427
+ const r = this.triangle(...args);
428
+
429
+ //Calculates the drawing area of the pattern with the center of gravity.
430
+ const cx = (arguments[0] + arguments[2] + arguments[4]) / 3;
431
+ const cy = (arguments[1] + arguments[3] + arguments[5]) / 3;
432
+ const w = this.max([Math.abs(cx - arguments[0]), Math.abs(cx - arguments[2]), Math.abs(cx - arguments[4])]) * 2;
433
+ const h = this.max([Math.abs(cy - arguments[1]), Math.abs(cy - arguments[3]), Math.abs(cy - arguments[5])]) * 2;
434
+ this._patternControler.applyPattern(cx - w /2, cy - h / 2, w, h, this);
435
+
436
+ //Calculates center position.(Not used)
437
+ /*
438
+ const minX = min(min(arguments[0], arguments[2]), arguments[4]);
439
+ const maxX = max(max(arguments[0], arguments[2]), arguments[4]);
440
+ const minY = min(min(arguments[1], arguments[3]), arguments[5]);
441
+ const maxY = max(max(arguments[1], arguments[3]), arguments[5]);
442
+ */
443
+ return r;
444
+ };
445
+
446
+
447
+ //quad
448
+ p5.prototype.quadPattern = function(...args)
449
+ {
450
+ _disableColor(this);
451
+ const r = this.quad(...args);
452
+
453
+ const minX = this.min([arguments[0], arguments[2], arguments[4], arguments[6]]);
454
+ const maxX = this.max([arguments[0], arguments[2], arguments[4], arguments[6]]);
455
+ const minY = this.min([arguments[1], arguments[3], arguments[5], arguments[7]]);
456
+ const maxY = this.max([arguments[1], arguments[3], arguments[5], arguments[7]]);
457
+
458
+ this._patternControler.applyPattern(minX, minY, maxX - minX, maxY - minY, this);
459
+ return r;
460
+ };
461
+
462
+
463
+ //vertex
464
+ p5.prototype.beginShapePattern = function(...args)
465
+ {
466
+ const r = this.beginShape(...args);
467
+ this._patternVertexInfo.reset();
468
+ return r;
469
+ };
470
+
471
+ p5.prototype.beginContourPattern = function(...args)
472
+ {
473
+ return this.beginContour(...args);
474
+ };
475
+
476
+ p5.prototype.vertexPattern = function(...args)
477
+ {
478
+ const r = this.vertex(...args);
479
+ this._patternVertexInfo.addVertex(arguments[0], arguments[1]);
480
+ return r;
481
+ };
482
+
483
+ p5.prototype.curveVertexPattern = function(...args)
484
+ {
485
+ const r = this.curveVertex(...args);
486
+ this._patternVertexInfo.addCurveVertex(arguments[0], arguments[1]);
487
+ return r;
488
+ };
489
+
490
+ p5.prototype.bezierVertexPattern = function(...args)
491
+ {
492
+ const r = this.bezierVertex(...args);
493
+ this._patternVertexInfo.addBezierVertex(
494
+ arguments[0], arguments[1],
495
+ arguments[2], arguments[3],
496
+ arguments[4], arguments[5]
497
+ );
498
+ return r;
499
+ };
500
+
501
+ p5.prototype.quadraticVertexPattern = function(...args)
502
+ {
503
+ const r = this.quadraticVertex(...args);
504
+ this._patternVertexInfo.addQuadraticVertex(
505
+ arguments[0], arguments[1],
506
+ arguments[2], arguments[3]
507
+ );
508
+ return r;
509
+ };
510
+
511
+ p5.prototype.endContourPattern = function(...args)
512
+ {
513
+ return this.endContour(...args);
514
+ };
515
+
516
+ p5.prototype.endShapePattern = function(...args)
517
+ {
518
+ _disableColor(this);
519
+ const r = this.endShape(...args);
520
+ const area = this._patternVertexInfo.culclateArea();
521
+ this._patternControler.applyPattern(area.x, area.y, area.w, area.h, this);
522
+ return r;
523
+ };
524
+
525
+ })();
526
+
527
+
528
+
529
+ // ---------------------------------------------------------------------------
530
+ // Pattern functions.
531
+ // ---------------------------------------------------------------------------
532
+
533
+ const PTN =
534
+ {
535
+ /**
536
+ * Noise pattern
537
+ * patternColors()[0] base color
538
+ * patternColors()[1] dot color
539
+ * @param {Number} _density Density of dots. default = 0.2
540
+ * Constrained between 0 and 1.
541
+ */
542
+ noise : function(_density = 0.2)
543
+ {
544
+ const func = function(_w, _h, _rt = window)
545
+ {
546
+ const density = _rt.constrain(_density, 0, 1);
547
+ const c = _rt.patternColors();
548
+
549
+ const num = _w * _h * density;
550
+ const ns = 0.01;
551
+
552
+ _rt.ellipseMode(_rt.CENTER);
553
+ _rt.rectMode(_rt.CORNER);
554
+ _rt.noStroke();
555
+
556
+ _rt.fill(c[0]);
557
+ _rt.rect(0, 0, _w, _h);
558
+
559
+ _rt.fill(c[1 % c.length]);
560
+ for(let i = 0; i < num; i++){
561
+ const x = _rt.random(_w);
562
+ const y = _rt.random(_h);
563
+ const dia = _rt.noise(x * ns, y * ns) * 0.5 + 1;
564
+ _rt.ellipse(x, y, dia, dia);
565
+ }
566
+ }
567
+ return func;
568
+ },
569
+
570
+ /**
571
+ * Noise gradient pattern
572
+ * patternColors()[0] base color
573
+ * patternColors()[1] dot color
574
+ * @param {Number} _density Density of dots. default = 0.2
575
+ */
576
+ noiseGrad : function(_density = 0.2)
577
+ {
578
+ const func = function(_w, _h, _rt = window)
579
+ {
580
+ const density = _rt.min(1, _density);
581
+ const c = _rt.patternColors();
582
+
583
+ const num = _w * _h * density;
584
+ const ns = 0.01;
585
+
586
+ _rt.rectMode(_rt.CORNER);
587
+ _rt.ellipseMode(_rt.CENTER);
588
+ _rt.noStroke();
589
+
590
+ _rt.fill(c[0]);
591
+ _rt.rect(0, 0, _w, _h);
592
+
593
+ _rt.fill(c[1 % c.length]);
594
+ for(let i = 0; i < num; i++){
595
+ const x = _rt.abs(_rt.randomGaussian()) / 5 * _w;
596
+ const y = _rt.random(_h);
597
+ const dia = _rt.noise(x * ns, y * ns) * 0.5 + 1;
598
+ _rt.ellipse(x, y, dia, dia);
599
+ }
600
+ }
601
+ return func;
602
+ },
603
+
604
+ /**
605
+ * Stripe pattern
606
+ * Fill the colors of patternColors() in order.
607
+ * @param {Number} _space Stripe space. default = 10
608
+ */
609
+ stripe : function(_space = 10)
610
+ {
611
+ const func = function(_w, _h, _rt = window)
612
+ {
613
+ _space = Math.abs(_space);
614
+ if(_space == 0)_space = 10;
615
+
616
+ const c = _rt.patternColors();
617
+
618
+ _rt.rectMode(_rt.CORNER);
619
+ _rt.noStroke();
620
+
621
+ let count = 0;
622
+
623
+ for(let x = 0; x <= _w + _space; x+= _space)
624
+ {
625
+ _rt.fill(c[count % c.length]);
626
+ _rt.rect(x, 0, Math.ceil(_space), _h);
627
+ count++;
628
+ }
629
+ }
630
+ return func;
631
+ },
632
+
633
+ /**
634
+ * Concentric circle stripe pattern.
635
+ * Fill the colors of patternColors() in order.
636
+ * @param {Number} _space Stripe space. default = 10
637
+ * @param {Number} _minRadius Minimum radius. default = 0
638
+ */
639
+ stripeCircle : function(_space = 25, _minRadius = 0)
640
+ {
641
+ const func = function(_w, _h, _rt = window)
642
+ {
643
+ _space = _rt.abs(_space);
644
+ if(_space == 0)_space = 25;
645
+
646
+ const c = _rt.patternColors();
647
+
648
+ const maxRadius = _rt.sqrt(_w * _w + _h * _h);
649
+ const num = _rt.ceil((maxRadius - _minRadius) / _space);
650
+
651
+ _rt.ellipseMode(_rt.CENTER);
652
+ _rt.noStroke();
653
+
654
+ for(let i = 0; i < num; i++)
655
+ {
656
+ _rt.fill(c[i % c.length]);
657
+ const radius = _minRadius + (num - 1 - i) * _space;
658
+ _rt.circle(_w / 2, _h / 2, radius * 2);
659
+ }
660
+ }
661
+ return func;
662
+ },
663
+
664
+ /**
665
+ * Concentric polygon stripe pattern.
666
+ * @param {Number} _vertNum Number of vertices in a polygon,
667
+ * constrained between 3 and 20. default = 3
668
+ * @param {Number} _space Stripe space. default = 10
669
+ * @param {Number} _minRadius Minimum radius. default = 0
670
+ */
671
+ stripePolygon : function(_vertNum = 3, _space = 25, _minRadius = 0)
672
+ {
673
+ const func = function(_w, _h, _rt = window)
674
+ {
675
+ _space = _rt.abs(_space);
676
+ if(_space == 0)_space = 25;
677
+
678
+ const vNum = _rt.int(_rt.constrain(_vertNum, 3, 30));
679
+ const c = _rt.patternColors();
680
+
681
+ const maxRadius = _rt.sqrt(_w * _w + _h * _h);
682
+ const num = _rt.ceil((maxRadius - _minRadius) / _space);
683
+
684
+ _rt.noStroke();
685
+
686
+ for(let i = 0; i < num; i++)
687
+ {
688
+ _rt.fill(c[i % c.length]);
689
+ const radius = _minRadius + (num - 1 - i) * _space;
690
+
691
+ _rt.beginShape();
692
+ for(let i = 0; i < vNum; i++)
693
+ {
694
+ const rad = i * Math.PI * 2 / vNum;
695
+ const x = _w / 2 + Math.cos(rad) * radius;
696
+ const y = _h / 2 + Math.sin(rad) * radius;
697
+ _rt.vertex(x, y);
698
+ }
699
+ _rt.endShape(_rt.CLOSE);
700
+ }
701
+ }
702
+ return func;
703
+ },
704
+
705
+
706
+ /**
707
+ * Radial stripe pattern.
708
+ * @param {Number} _angleSpan Stripe angle space. default = PI / 4,
709
+ * specified in radians or degrees, depending on current angleMode
710
+ */
711
+ stripeRadial : function(_angleSpan = 1)
712
+ {
713
+ const func = function(_w, _h, _rt = window)
714
+ {
715
+ _angleSpan = _rt.abs(_angleSpan);
716
+ if(_angleSpan == 0)_angleSpan = 1;
717
+
718
+ const c = _rt.patternColors();
719
+ const tau = _rt._angleMode == _rt.DEGREES ? 360 : _rt.TAU;
720
+
721
+ _rt.ellipseMode(_rt.CENTER);
722
+ _rt.noStroke();
723
+
724
+ let count = 0;
725
+ const dia = _rt.sqrt(_w * _w + _h * _h);
726
+ for(let r = 0; r < tau; r += _angleSpan)
727
+ {
728
+ //Error measures
729
+ const endRad = r + _angleSpan > tau ? 0.00001 : r + _angleSpan;
730
+ _rt.fill(c[count % c.length]);
731
+ _rt.arc(_w / 2, _h /2, dia, dia, r, endRad + 0.0001);
732
+ count++;
733
+ }
734
+ }
735
+ return func;
736
+ },
737
+
738
+
739
+ /**
740
+ * Wave pattern
741
+ * patternColors()[0] base color
742
+ * patternColors()[1] wave color
743
+ * @param {Number} _waveW Wave width. default = 100
744
+ * @param {Number} _waveH Wave height. default = 20
745
+ * @param {Number} _space Line spacing. default = 20
746
+ * @param {Number} _weight Line weight. default = 5
747
+ */
748
+ wave : function(_waveW = 100, _waveH = 10, _space = 20, _weight = 5)
749
+ {
750
+ const func = function(_w, _h, _rt = window)
751
+ {
752
+ _space = _rt.abs(_space);
753
+ if(_space == 0)_space = 20;
754
+ _waveW = _rt.abs(_waveW);
755
+ if(_waveW == 0)_waveW = 100;
756
+
757
+ const c = _rt.patternColors();
758
+
759
+ const vertSpan = 3;
760
+ _rt.rectMode(_rt.CORNER);
761
+ _rt.noStroke();
762
+
763
+ _rt.fill(c[0]);
764
+ _rt.rect(0, 0, _w, _h);
765
+
766
+ const tileColours = c.slice(1);
767
+ let count = 0;
768
+ for(let y = -_waveH; y <= _h + _waveH; y+= _space)
769
+ {
770
+ _rt.fill(tileColours[count % tileColours.length])
771
+ _rt.beginShape();
772
+
773
+ for(let x = 0; x < _w; x += vertSpan)
774
+ {
775
+ const rad = x / _waveW * _rt.TAU;
776
+ _rt.vertex(x, y + Math.sin(rad) * _waveH);
777
+ }
778
+
779
+ _rt.vertex(_w, y + Math.sin(_w / _waveW * Math.PI * 2) * _waveH);
780
+ for(let x = _w; x > 0; x -= vertSpan)
781
+ {
782
+ const rad = x / _waveW * Math.PI * 2;
783
+ _rt.vertex(x, y + _weight + Math.sin(rad) * _waveH);
784
+ }
785
+ _rt.vertex(0, y + _weight + Math.sin(0) * _waveH);
786
+
787
+ _rt.endShape(_rt.CLOSE);
788
+ count++;
789
+ }
790
+ }
791
+ return func;
792
+ },
793
+
794
+ /*
795
+ Private function.
796
+ Generate tiling pattern functions.
797
+ */
798
+ _customTiling : function(_spaceX, _spaceY, _tileFunc, _useOffset = false)
799
+ {
800
+ const func = function(_w, _h, _rt)
801
+ {
802
+ _spaceX = _rt.abs(_spaceX);
803
+ if(_spaceX == 0)_spaceX = 50;
804
+ _spaceY = _rt.abs(_spaceY);
805
+ if(_spaceY == 0)_spaceY = 50;
806
+
807
+ const c = _rt.patternColors();
808
+ _rt.rectMode(_rt.CORNER);
809
+ _rt.noStroke();
810
+
811
+ _rt.fill(c[0]);
812
+ _rt.rect(0, 0, _w, _h);
813
+
814
+ const tileColours = c.slice(1);
815
+ let yi = 0,
816
+ count = 0;
817
+ for(let y = 0; y <= _h + _spaceY /2; y += _spaceY)
818
+ {
819
+ let xi = 0;
820
+ let offset = yi % 2 == 1 && _useOffset ? -_spaceX / 2 : 0;
821
+ for(let x = offset; x <= _w + _spaceX /2; x += _spaceX)
822
+ {
823
+ _rt.push();
824
+ _rt.translate(x, y);
825
+ _rt.fill(tileColours[count % tileColours.length])
826
+ _tileFunc(_rt, xi, yi);
827
+ _rt.pop();
828
+ xi++;
829
+ count++;
830
+ }
831
+ yi++;
832
+ }
833
+ }
834
+ return func;
835
+ },
836
+
837
+ /**
838
+ * Dot pattern
839
+ * patternColors()[0] base color
840
+ * patternColors()[1] Checked color
841
+ * @param {Number} _space Dot spacing. default = 15
842
+ * @param {Number} _dia Dot diameter. default = 15
843
+ */
844
+ dot : function(_space = 15, _dia = 7)
845
+ {
846
+ const func = PTN._customTiling(
847
+ _space,
848
+ _space,
849
+ function(_rt)
850
+ {
851
+ _rt.noStroke();
852
+ _rt.ellipseMode(_rt.CENTER);
853
+ _rt.circle(0, 0, _dia);
854
+ },
855
+ false
856
+ );
857
+ return func;
858
+ },
859
+
860
+ /**
861
+ * Checked pattern
862
+ * patternColors()[0] base color
863
+ * patternColors()[1] Checked color
864
+ * @param {Number} _checkW Width of checkered pattern. default = 10
865
+ * @param {Number} _checkH Height of checkered pattern (Optional)
866
+ */
867
+ checked : function(...args)
868
+ {
869
+ let w, h;
870
+ if(arguments.length == 0){ w = 10; h = 10;}
871
+ else if(arguments.length == 1){w = arguments[0]; h = w;}
872
+ else{w = arguments[0]; h = arguments[1];}
873
+
874
+ const func = PTN._customTiling(
875
+ w * 2,
876
+ h,
877
+ function(_rt)
878
+ {
879
+ _rt.noStroke();
880
+ _rt.rectMode(_rt.CORNER);
881
+ _rt.rect(0, 0, w, h);
882
+ },
883
+ true
884
+ );
885
+ return func;
886
+ },
887
+
888
+ /**
889
+ * Cross pattern
890
+ * patternColors()[1] base color
891
+ * patternColors()[0] line color
892
+ * @param {Number} _space Line spacing. default = 20
893
+ * @param {Number} _weight Line weight. default = 5
894
+ */
895
+ cross : function(_space = 20, _weight = 5)
896
+ {
897
+ const func = function(_w, _h, _rt = window)
898
+ {
899
+ const c = _rt.patternColors();
900
+ _rt.rectMode(_rt.CORNER);
901
+ _rt.fill(c[0]);
902
+ _rt.rect(0, 0, _w, _h);
903
+
904
+ const tileColours = c.slice(1);
905
+ let count = 0;
906
+ for(let y = 0; y < _h; y+= _space) {
907
+ _rt.fill(tileColours[count % tileColours.length])
908
+ _rt.rect(0, y + _space / 2 - _weight /2, _w, _weight);
909
+ count++;
910
+ }
911
+ for(let x = 0; x < _w; x+= _space) {
912
+ _rt.fill(tileColours[count % tileColours.length])
913
+ _rt.rect(x + _space / 2 - _weight / 2, 0, _weight, _h);
914
+ count++;
915
+ }
916
+ }
917
+ return func;
918
+ },
919
+
920
+ /**
921
+ * Triangle pattern
922
+ * patternColors()[0] base color
923
+ * patternColors()[1] line color
924
+ * @param {Number} _triW Triangle width. default = 20
925
+ * @param {Number} _triH Triangle height. default = 20
926
+ */
927
+ triangle : function(_triW = 20, _triH = 20)
928
+ {
929
+ const func = PTN._customTiling(
930
+ _triW,
931
+ _triH,
932
+ function(_rt)
933
+ {
934
+ _rt.noStroke();
935
+ _rt.triangle(0, 0, _triW, 0, _triW /2, _triH);
936
+ },
937
+ true
938
+ );
939
+ return func;
940
+ }
941
+
942
+ };
943
+
944
+ export { PTN };