├── .gitignore
├── LICENSE
├── README.md
├── cloud.png
├── css
├── main.css
└── print.css
├── custom_ui.js
├── generators.js
├── index.html
├── print
├── extra_data.js
├── index.html
└── print.js
└── sketch.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | .DS_Store
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Daniel Shiffman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Community Clouds
2 |
3 | This software is for generating clouds for name tags for the Processing
4 | Community Day. You can try out all of the current submissions on the GitHub
5 | pages site:
6 |
7 | https://codingtrain.github.io/CommunityClouds/
8 |
9 |
10 | ## About Processing Community Day
11 |
12 | > Community Day will bring together members of the community to discuss work,
13 | > share ideas and experiences, and promote outreach to new members,
14 | > particularly those who are underrepresented in creative and technological
15 | > fields. The event is a time to celebrate, reflect, and look forward.
16 |
17 | > Organized by the Processing Foundation, the day-long event is for anyone
18 | > interested in creative computing, software literacy, accessibility, and
19 | > diversity in the fields of art, technology, and design. The event will be a
20 | > mix of talks and demos by people from all backgrounds within the Processing
21 | > community, as well as the Processing Foundation members, Fellows, and others
22 | > who use Processing, p5.js, and all the related variants in their work.
23 |
24 | Interested? Find out more at the
25 | [Processing Community Day Page][1].
26 |
27 | ## Contributing
28 |
29 | The main theme is, of course, the community and so it would be great if you
30 | want to submit functions to generate cloud shapes! If you are new to git, you
31 | can check out [Git and GitHub for Poets][2], otherwise feel free to fork this
32 | repository and create a Pull Request with your changes. Need help? Feel free
33 | to raise an issue if there's anything we can help you with!
34 |
35 | To add a new cloud generator, simply edit the `generators.js` file and create
36 | a new function following the example! Your new generator should then show up
37 | in the list on the main page!
38 |
39 | ### What are we looking for?
40 |
41 | Anything really! Perhaps you have a design in your mind,
42 | or perhaps you can take inspiration from this cloud drawing from Processing Day organizer Taeyoon Choi:
43 |
44 | 
45 |
46 | [0]: https://codingtrain.github.io/CommunityClouds/
47 | [1]: https://day.processing.org/
48 | [2]: https://www.youtube.com/watch?v=BCQHnlnPusY&list=PLRqwX-V7Uu6ZF9C0YMKuns9sLDzK6zoiV
49 |
--------------------------------------------------------------------------------
/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodingTrain/CommunityClouds/321c0cf8848e2ce6ed71d51294d02bcb8d5034e9/cloud.png
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic);
2 |
3 | * {
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: border-box;
7 | color: #959595;
8 | font-family: 'Open Sans', sans-serif;
9 | transition-timing-function: cubic-bezier(0.57, 0.0, 0.1, 1.0);
10 | }
11 |
12 | body,
13 | html {
14 | height: 100%;
15 | background: #fff;
16 | font-size: 16px;
17 | }
18 |
19 |
20 | /* Generic styles */
21 |
22 | .l-float {
23 | float: left;
24 | }
25 |
26 | .r-float {
27 | float: right;
28 | }
29 |
30 |
31 | /* Page styling */
32 |
33 | #sketch-contain {
34 | margin: 0 auto;
35 | text-align: center;
36 | font-size: 0;
37 | height: 100%;
38 | width: 100%;
39 | }
40 |
41 | .form-contain,
42 | .selection-container .opt-all,
43 | input[type="submit"] {
44 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.2);
45 | }
46 |
47 | .form-contain {
48 | opacity: 0.5;
49 | width: 400px;
50 | height: auto;
51 | margin: 0 auto;
52 | text-align: left;
53 | position: absolute;
54 | background: #fff;
55 | transition: all 300ms 200ms;
56 | }
57 |
58 | .form-contain:hover {
59 | opacity: 1;
60 | transition: all 300ms;
61 | }
62 |
63 | .form-contain#form-primary {
64 | top: 36px;
65 | left: 36px;
66 | }
67 |
68 | .form-contain#form-secondary {
69 | bottom: 36px;
70 | left: 36px;
71 | padding: 12px;
72 | }
73 |
74 | .download-svg {
75 | opacity: .3;
76 | display: block;
77 | width: auto;
78 | height: auto;
79 | margin: 0 auto;
80 | text-align: left;
81 | position:absolute;
82 | bottom: 36px;
83 | right: 36px;
84 | padding: 12px;
85 | background: #fff;
86 | -webkit-border-radius: 5px;
87 | -moz-border-radius: 5px;
88 | border-radius: 5px;
89 | -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.2);
90 | -moz-box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.2);
91 | box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.2);
92 |
93 | -webkit-transition: all .3s cubic-bezier(.57,.01,.1,1);
94 | -moz-transition: all .3s cubic-bezier(.57,.01,.1,1);
95 | -o-transition: all .3s cubic-bezier(.57,.01,.1,1);
96 | transition: all .3s cubic-bezier(.57,.01,.1,1);
97 |
98 | cursor: pointer;
99 | }
100 |
101 | .download-svg:hover {
102 |
103 | opacity: 1;
104 | -webkit-transition: all .3s cubic-bezier(.57,.01,.1,1);
105 | -moz-transition: all .3s cubic-bezier(.57,.01,.1,1);
106 | -o-transition: all .3s cubic-bezier(.57,.01,.1,1);
107 | transition: all .3s cubic-bezier(.57,.01,.1,1);
108 | }
109 |
110 | .field-information {
111 | position: absolute;
112 | right: 0;
113 | width: auto;
114 | height: auto;
115 | padding: 25px;
116 | padding-bottom: 0px;
117 | overflow-y: auto;
118 | }
119 |
120 | .tooltip-title {
121 | color: #b300ff;
122 | font-weight: bold;
123 | }
124 |
125 | .fc-top,
126 | .fc-lower {
127 | display: block;
128 | width: 100%;
129 | height: auto;
130 | background: #fff;
131 | padding: 0;
132 | }
133 |
134 | .fc-lower,
135 | .fc-name {
136 | background: transparent;
137 | }
138 |
139 | .attribution {
140 | display: table;
141 | width: 100%;
142 | max-width: 400px;
143 | height: auto;
144 | max-height: 31px;
145 | white-space: nowrap;
146 | font-weight: 700;
147 | font-size: 0;
148 | }
149 |
150 | #attrib-title,
151 | #attrib-author {
152 | display: table-cell;
153 | font-size: 0.9rem;
154 | }
155 |
156 | #attrib-title {
157 | color: #fff;
158 | background: #b300ff;
159 | padding: 6px 12px;
160 | width: 1%;
161 | }
162 |
163 | #attrib-author {
164 | background: #fff;
165 | font-size: 0.9rem;
166 | padding: 4px 12px;
167 | border: 2px solid #b300ff;
168 | }
169 |
170 | #attrib-author .by-sep {
171 | color: #c3c3c3;
172 | }
173 |
174 | #attrib-author #author-name {
175 | color: #b300ff;
176 | }
177 |
178 | .selection-container {
179 | z-index: 1000;
180 | position: relative;
181 | }
182 |
183 | .selection-container .select-input {
184 | width: 100%;
185 | max-width: 400px;
186 | height: 31px;
187 | font-weight: 500;
188 | font-size: 0.9rem;
189 | background: #fff;
190 | }
191 |
192 | .selection-container li {
193 | list-style-type: none;
194 | cursor: pointer;
195 | }
196 |
197 | .selection-container .opt-cur {
198 | padding: 6px 12px;
199 | position: relative;
200 | }
201 |
202 | .selection-container .opt-cur:after {
203 | content: '';
204 | display: inline-block;
205 | height: 6px;
206 | width: 6px;
207 | border: 3px solid #b8b8b8;
208 | border-bottom-width: 0;
209 | border-left-width: 0;
210 | position: absolute;
211 | top: 50%;
212 | right: 0%;
213 | margin-top: -3px;
214 | margin-right: 15px;
215 | transform: rotate(315deg);
216 | transition: all 150ms;
217 | }
218 |
219 | .selection-container.showing .opt-cur:after {
220 | margin-top: -6px;
221 | transform: rotate(135deg);
222 | }
223 |
224 | .selection-container .opt-all {
225 | background: #fff;
226 | min-height: 100px;
227 | max-height: calc(100vh - 300px);
228 | opacity: 0;
229 | pointer-events: none;
230 | overflow-y: scroll;
231 | width: 100%;
232 | z-index: 1000;
233 | transition: opacity 200ms;
234 | }
235 |
236 | .selection-container.showing .opt-all {
237 | opacity: 1;
238 | pointer-events: auto;
239 | }
240 |
241 | .group {
242 | padding: 8px 0;
243 | }
244 |
245 | .group:not(:last-child) {
246 | border-bottom: 2px solid hsl(0, 0%, 96%);
247 | }
248 |
249 | .selection-container .material-select-option {
250 | width: 100%;
251 | padding: 6px 12px 6px 10px;
252 | border-left: 2px solid #fff;
253 | }
254 |
255 | .selection-container .material-select-option:hover {
256 | background: #f7f7f7;
257 | color: #b300ff;
258 | border-left-color: #b300ff;
259 | }
260 |
261 |
262 | /* Styling inputs/buttons */
263 |
264 | input {
265 | border: none;
266 | outline: none;
267 | }
268 |
269 | input.jscolor {
270 | padding: 2px 6px;
271 | }
272 |
273 | input[type="submit"] {
274 | color: #fff;
275 | background: #b300ff;
276 | padding: 7px 20px;
277 | font-weight: 700;
278 | font-size: 0.9em;
279 | border-radius: 5px;
280 | margin: 25px 0 0 0;
281 | cursor: pointer;
282 | }
283 |
284 | input[type="submit"]:disabled,
285 | input[type="submit"]:active {
286 | box-shadow: none;
287 | }
288 |
289 | input[type="submit"]:disabled {
290 | background: #d8d8d8;
291 | cursor: not-allowed;
292 | }
293 |
294 | input[type="submit"]:active {
295 | background: #2064e6;
296 | }
297 |
298 | input[type="text"] {
299 | width: 100%;
300 | max-width: 400px;
301 | padding: 4px 0 6px;
302 | margin-top: 26px;
303 | font-weight: 700;
304 | font-size: 16px;
305 | color: #8c8c8c;
306 | background: transparent;
307 | border-bottom: 2px solid #d8d8d8;
308 | }
309 |
310 | input[type="text"]:invalid {
311 | box-shadow: none;
312 | }
313 |
314 | input[type="text"]:focus {
315 | border-bottom-color: #b300ff;
316 | color: #464c57;
317 | }
318 |
319 | input[type="text"].invalid {
320 | border-bottom: 3px solid #f43939;
321 | }
322 |
323 | form .text {
324 | width: 100%;
325 | height: 80px;
326 | overflow: hidden;
327 | position: relative;
328 | }
329 |
330 | .label-field {
331 | font-size: 16px;
332 | cursor: text;
333 | position: absolute;
334 | top: 30px;
335 | transition: all 300ms, color 100ms;
336 | }
337 |
338 | .label-field-filled,
339 | .label-field-focus {
340 | top: 12px;
341 | font-size: 11px;
342 | }
343 |
344 | .label-field-filled {
345 | color: #acacac;
346 | }
347 |
348 | .label-field-focus {
349 | color: #b300ff;
350 | }
351 |
352 | span .error-info {
353 | position: absolute;
354 | bottom: 0;
355 | right: 0;
356 | font-size: 13px;
357 | color: #f43939;
358 | cursor: text;
359 | width: auto;
360 | display: inline-block;
361 | height: auto;
362 | text-align: right;
363 | }
364 |
--------------------------------------------------------------------------------
/css/print.css:
--------------------------------------------------------------------------------
1 | #svg-wrap {
2 | width: 100%;
3 | max-width: 133vh;
4 | }
5 |
6 | #svg-contain {
7 | position: relative;
8 | width: 100%;
9 | height: 0;
10 | padding-bottom: 75%;
11 | }
12 |
13 | #svg-contain svg {
14 | position: absolute;
15 | width: 100%;
16 | height: 100%;
17 | }
18 |
19 |
20 | #svg-contain.transparent {
21 | background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
22 | background-size: 20px 20px;
23 | background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
24 | }
25 |
26 | #svg-contain.white {
27 | background: #FFF;
28 | }
29 |
30 | #svg-contain.red {
31 | background: #F00;
32 | }
33 |
34 |
35 | #page-template {
36 | width: 0 !important;
37 | height: 0 !important;
38 | }
39 |
40 | #pages svg {
41 | width: 240px;
42 | height: auto;
43 | margin: 10px;
44 | }
45 |
46 | @media print {
47 | #Current {
48 | display: none;
49 | }
50 |
51 | #pages svg {
52 | width: 100%;
53 | height: auto;
54 | margin: 0;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/custom_ui.js:
--------------------------------------------------------------------------------
1 | class FormFields {
2 | constructor() {
3 | this.id = null;
4 | this.nodesRef = null;
5 | }
6 |
7 | setId() {
8 | let id = "",
9 | length = 32,
10 | charSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
11 | for(let i = 0; i < length; i++) {
12 | let index = Math.floor(Math.random() * charSet.length);
13 | id += charSet[index];
14 | }
15 | return id;
16 | }
17 | }
18 |
19 | class MaterialText extends FormFields {
20 | constructor(toolTip, rxPattern, rxDesc, required, name, label, value) {
21 | super();
22 | this.id = this.setId();
23 | this.toolTip = toolTip || "";
24 | this.rxPattern = rxPattern || "";
25 | this.rxDesc = rxDesc || "";
26 | this.required = required || false;
27 | this.name = name || "";
28 | this.label = label || "";
29 | this.value = value || "";
30 | this.validInput = "";
31 | this.containerNode = "";
32 | this.labelNode = "";
33 | this.inputNode = "";
34 | this.nodesRef = this.generateTree();
35 | this.validity = true;
36 |
37 | this.addTextFieldListeners();
38 |
39 | document.getElementById("clouds-form-options")
40 | .addEventListener("keypress", e => {
41 | let key = e.charCode || e.keyCode || 0;
42 | if(key === 13) e.preventDefault();
43 | });
44 | }
45 |
46 | generateTree() {
47 | let c = document.createElement("div"),
48 | l = document.createElement("label"),
49 | i = document.createElement("input");
50 |
51 | c.classList.add("text");
52 |
53 | l.classList.add("label-field");
54 | l.innerText = this.label;
55 | l.setAttribute("for", this.id);
56 |
57 | i.id = this.id;
58 | i.value = this.value;
59 | i.setAttribute("type", "text");
60 | i.setAttribute("name", this.name);
61 | if(this.required) {
62 | i.setAttribute("required", "");
63 | }
64 |
65 | c.appendChild(l);
66 | c.appendChild(i);
67 |
68 | this.containerNode = c;
69 | this.labelNode = l;
70 | this.inputNode = i;
71 |
72 | return c;
73 | }
74 |
75 | modifyTextFieldLabel(e) {
76 | if(!this.labelNode) {
77 | return;
78 | }
79 | this.labelNode.classList.toggle("label-field-focus", this.focused);
80 | this.labelNode.classList.toggle("label-field-filled", this.value);
81 | }
82 |
83 | modifyTooltip(e) {
84 | let toolTip;
85 | /**if(this.toolTip && this.inputNode === document.activeElement) {
86 | toolTip = this.label ? "" + this.label + "" + this.toolTip : this.toolTip;
87 | tooltipContainer.innerHTML = toolTip;
88 | } else {
89 | return;
90 | }**/
91 | }
92 |
93 | showErrorMessages() {
94 | let errorInfo = this.containerNode.querySelectorAll(".error-info")[0];
95 | if(this.inputNode.classList.contains("invalid")) {
96 | if(!errorInfo) {
97 | errorInfo = document.createElement("span");
98 | if(this.required) {
99 | errorInfo.innerText = "Required; " + this.rxDesc;
100 | } else {
101 | errorInfo.innerText = this.rxDesc;
102 | }
103 | errorInfo.classList.add("error-info");
104 | this.containerNode.appendChild(errorInfo);
105 | }
106 | } else if(errorInfo) {
107 | this.containerNode.removeChild(errorInfo);
108 | }
109 | }
110 |
111 | validateInputEvent(e) {
112 | let rx = new RegExp(this.rxPattern);
113 | this.validity = rx.test(this.value);
114 |
115 | if(this.rxPattern && this.rxPattern.length > 0) {
116 | if(this.validity) {
117 | this.inputNode.className = "";
118 | } else if(!this.value.length > 0) {
119 | this.inputNode.className = "";
120 | if(!this.required) {
121 | this.validity = true;
122 | }
123 | } else {
124 | this.inputNode.className = "";
125 | this.inputNode.classList.add("invalid");
126 | }
127 | }
128 | if(this.validity || this.value === "") {
129 | this.validInput = this.value;
130 | }
131 |
132 | this.showErrorMessages();
133 |
134 | return true;
135 | }
136 |
137 | addTextFieldListeners() {
138 | let modifyTextFieldLabel = this.modifyTextFieldLabel.bind(this),
139 | modifyTooltip = this.modifyTooltip.bind(this),
140 | validateInputEvent = this.validateInputEvent.bind(this);
141 |
142 | this.inputNode.addEventListener("focus", modifyTextFieldLabel);
143 | this.inputNode.addEventListener("blur", modifyTextFieldLabel);
144 | this.inputNode.focus();
145 | this.inputNode.blur();
146 |
147 | this.inputNode.addEventListener("focus", modifyTooltip);
148 | this.inputNode.addEventListener("blur", modifyTooltip);
149 | this.inputNode.addEventListener("input", validateInputEvent);
150 | this.inputNode.addEventListener("onchange", validateInputEvent);
151 |
152 | this.validateInputEvent();
153 | }
154 |
155 | get value() {
156 | this.value = this.inputNode.value || "";
157 | return this._value;
158 | }
159 |
160 | set value(value) {
161 | return this._value = value;
162 | }
163 |
164 | get focused() {
165 | return this.inputNode === document.activeElement;
166 | }
167 | }
168 |
169 | class MaterialSelect extends FormFields {
170 | constructor(selectableOptions, toolTip, sorted, changeCallback) {
171 | super();
172 | this.id = this.setId();
173 | this.toolTip = toolTip || "";
174 | this.value = "";
175 | this.containerNode = "";
176 | this.ulNode = "";
177 | this.curOpt = "";
178 | this.curIndex = "";
179 | this.passedOrder = [];
180 | this.optionsInOrder = [];
181 | this.curOptNode = "";
182 | this.optAllNode = "";
183 | this.optionsNodes = [];
184 | this.groupNodes = [];
185 | this.groups = {};
186 | this.default = "";
187 | this.selectableOptions = selectableOptions || {};
188 | this.sorted = sorted || false;
189 | this.changeCallback = changeCallback || null;
190 | this.nodesRef = this.generateTree();
191 |
192 | this.addSelectorListeners();
193 | }
194 |
195 | generateTree() {
196 | let s = document.createElement("div"), // Selector container
197 | u = document.createElement("ul"), // Outer ul
198 | c = document.createElement("li"), // Current option
199 | a = document.createElement("li"); // All options
200 |
201 | s.id = this.id;
202 | s.classList.add("selection-container");
203 | s.appendChild(u);
204 |
205 | u.classList.add("select-input");
206 | u.appendChild(c);
207 | u.appendChild(a);
208 |
209 | c.id = "opt-cur";
210 | c.classList.add("opt-cur");
211 |
212 | a.id = "opt-all";
213 | a.classList.add("opt-all");
214 |
215 | this.containerNode = s;
216 | this.ulNode = u;
217 | this.curOptNode = c;
218 | this.optAllNode = a;
219 |
220 | this.handleGrouping();
221 |
222 | this.handleSorting();
223 |
224 | // Generate all options
225 | this.optionsInOrder.forEach(key => {
226 | let item = this.selectableOptions[key],
227 | preSortIndex = this.passedOrder.indexOf(key),
228 | index = item.index,
229 | group = item.group;
230 |
231 | let tmp = document.createElement("li");
232 | tmp.innerText = item.value;
233 | this.passedOrder[preSortIndex] = key;
234 | tmp.dataset.optionIndex = index;
235 | tmp.id = key.split(" ").join("_");
236 | tmp.classList.add("material-select-option");
237 | this.optionsNodes.push(tmp);
238 |
239 | this.groupNodes[group].appendChild(tmp);
240 | });
241 |
242 | for(let key in this.groupNodes) {
243 | a.appendChild(this.groupNodes[key]);
244 | }
245 |
246 | this.setOptionByIndex(this.selectableOptions[this.default].index);
247 |
248 | return s;
249 | }
250 |
251 | handleGrouping() {
252 | for(let key in this.selectableOptions){
253 | let curItem = this.selectableOptions[key],
254 | curItemGroup = curItem.group,
255 | isDefault = curItem.default || false;
256 | if(isDefault){
257 | if(this.default){
258 | throw new Error("Only one default option may be set.");
259 | }
260 | this.default = key;
261 | }
262 | if(!curItemGroup){
263 | curItem.group = "no-group";
264 | curItemGroup = "no-group";
265 | }
266 | if(!(curItemGroup in this.groups)) {
267 | this.groups[curItemGroup] = {};
268 | }
269 | this.groups[curItemGroup][key] = curItem;
270 | }
271 | // Generate top-level group nodes
272 | for(let key in this.groups){
273 | let g = document.createElement("div"); // Group container
274 | g.classList.add("group");
275 | g.id = "group-" + key;
276 | this.groupNodes[key] = g;
277 | };
278 | }
279 |
280 | handleSorting() {
281 | let opts = this.selectableOptions,
282 | k = Object.keys;
283 | this.passedOrder = k(opts);
284 | if(this.sorted) {
285 | // Sort group names before sorting elements in groups
286 | let groupSort = k(this.groups).sort((a, b) => a.localeCompare(b)),
287 | indexTmp = -1;
288 | for(let i in groupSort){
289 | let itemSort = k(this.groups[groupSort[i]]).sort((a, b) => a.localeCompare(b));
290 | itemSort.forEach(key => {
291 | indexTmp++;
292 | opts[key].index = indexTmp;
293 | this.optionsInOrder[indexTmp] = key;
294 | });
295 | }
296 | } else {
297 | let indexTmp = -1;
298 | k(opts).forEach(key => {
299 | indexTmp++;
300 | opts[key].index = indexTmp;
301 | this.optionsInOrder[indexTmp] = key;
302 | });
303 | }
304 | }
305 |
306 | clickOffReset(e) {
307 | let target = e.target;
308 | let resetCallback = this.clickOffReset.bind(this);
309 | if(!this.containerNode.contains(target)){
310 | this.containerNode.classList.remove("showing");
311 | window.removeEventListener("click", resetCallback);
312 | }
313 | }
314 |
315 | chooseOptions(e) {
316 | let target = e.target,
317 | isCurOpt = target === this.curOptNode,
318 | resetCallback = this.clickOffReset.bind(this);
319 | window.addEventListener("click", resetCallback);
320 | if(isCurOpt) {
321 | this.containerNode.classList.toggle("showing");
322 | return;
323 | }
324 | else {
325 | this.containerNode.classList.remove("showing");
326 | window.removeEventListener("click", resetCallback);
327 | }
328 | if(target.classList.contains("material-select-option")) {
329 | this.curIndex = target.dataset.optionIndex;
330 | this.setOptionByIndex(this.curIndex);
331 | }
332 | if(this.changeCallback !== null) {
333 | this.changeCallback();
334 | }
335 | }
336 |
337 | addSelectorListeners(){
338 | let chooseOptions = this.chooseOptions.bind(this);
339 | this.containerNode.addEventListener("click", chooseOptions);
340 | }
341 |
342 | setOptionByIndex(ind){
343 | let opts = this.selectableOptions,
344 | curOption = this.optionsInOrder[ind];
345 | this.curOpt = curOption;
346 | this.value = opts[curOption].value;
347 | this.curOptNode.innerText = this.value;
348 | }
349 |
350 | nextItem(){
351 | if(this.curIndex < this.optionsInOrder.length - 1){
352 | this.curIndex++;
353 | this.setOptionByIndex(this.curIndex);
354 | if(this.changeCallback) {
355 | this.changeCallback();
356 | }
357 | }
358 | return;
359 | }
360 |
361 | previousItem(){
362 | if(this.curIndex > 0){
363 | this.curIndex--;
364 | this.setOptionByIndex(this.curIndex);
365 | if(this.changeCallback) {
366 | this.changeCallback();
367 | }
368 | }
369 | return;
370 | }
371 |
372 | get PresortIndex(){
373 | return this.passedOrder.indexOf(this.curOpt);
374 | }
375 |
376 | }
377 |
--------------------------------------------------------------------------------
/generators.js:
--------------------------------------------------------------------------------
1 | // Edit this file to add your cloud design!
2 |
3 | // Just write a function with a unique name like:
4 | // function perlinNoiseCloud() {}
5 | // and then add a line of code that "registers" it:
6 | // register(perlinNoiseCloud, "Perlin Noise Cloud", "Daniel Shiffman");
7 | // Here's an example below!
8 |
9 | // Example rounded rectangle cloud
10 | function rectangle() {
11 | // Draw your cloud here
12 | rect(50, 50, width - 100, height - 100, 50);
13 | // Return an internal rectangle that it is safe to draw text within. Of the
14 | // form [top_left, top_right, width, height]
15 | return [100, 100, width - 200, height - 200];
16 | }
17 |
18 | // Register your function with register(function, style_name, author_name)
19 | register(rectangle, "Example", "example");
20 |
21 | /* ------ Add your custom cloud generators below! ------ */
22 |
23 |
24 | //*************************************************
25 |
26 | function PCDCloud() {
27 | translate(width / 2, height / 2);
28 | angleMode(DEGREES);
29 | strokeWeight(1);
30 | noFill();
31 | let stepsize = 5;
32 | beginShape();
33 | let a = 0;
34 |
35 | for (let angle = 0; angle < 360; angle += stepsize) {
36 | let offset = abs(sin(a)) * 20;
37 | let xradius = 200 + offset;
38 | let yradius = 100 + offset;
39 | let x = xradius * cos(angle);
40 | let y = yradius * sin(angle);
41 | vertex(x, y);
42 | a = a + 55;
43 | }
44 | endShape(CLOSE);
45 | }
46 |
47 | register(PCDCloud, "PCD Day", "Processing Community");
48 |
49 |
50 | function ellipseCloud() {
51 | const circleRadius = width / 8;
52 |
53 | const cloudWidth = width - 100 - circleRadius;
54 | const cloudHeight = height - 100 - circleRadius;
55 |
56 | // Getting number of circles based on the width of the cloud and the cloud radius size.
57 | const circleAmount = cloudWidth / (circleRadius * 0.5) * 2;
58 |
59 | push();
60 | translate(width / 2, height / 2);
61 |
62 | // Drawing outside circles (with stroke)
63 | for (let i = 0; i < circleAmount; i++) {
64 | drawOuterCirc(i);
65 | }
66 |
67 | // Drawing inner circles which hide the inner stroke of the outer circles
68 | for (let i = 0; i < circleAmount; i++) {
69 | drawInnerCirc(i);
70 | }
71 |
72 | // Filling the middle with white for name
73 | noStroke();
74 | ellipse(0, 0, cloudWidth, cloudHeight);
75 | pop();
76 |
77 | function drawOuterCirc(num) {
78 | const angle = TWO_PI / circleAmount * num;
79 |
80 | const circleX = cloudWidth / 2 * cos(angle);
81 | const circleY = cloudHeight / 2 * sin(angle);
82 |
83 | push();
84 | translate(circleX, circleY);
85 | ellipse(0, 0, circleRadius, circleRadius);
86 | pop();
87 | }
88 | function drawInnerCirc(num) {
89 | const angle = TWO_PI / circleAmount * num;
90 |
91 | // * 0.99 to still show the stroke of the outer circles
92 | const circleX = cloudWidth / 2 * cos(angle) * 0.99;
93 | const circleY = cloudHeight / 2 * sin(angle) * 0.99;
94 |
95 | push();
96 | noStroke();
97 | translate(circleX, circleY);
98 | ellipse(0, 0, circleRadius, circleRadius);
99 | pop();
100 | }
101 |
102 | return [100, 100, width - 200, height - 200];
103 | }
104 |
105 | register(ellipseCloud, "Ellipse Cloud", "Raqbit");
106 |
107 | function marmsCloud() {
108 | noStroke();
109 | var a = 400;
110 | var b = 200;
111 | var xc = 200;
112 | var yc = 100;
113 |
114 | var n = random(80,120);
115 | for(var i = 0; i < n; i++){
116 | var r = 2*random(30,50);
117 | var rx = r + random(-3,5);
118 | var ry = r + random(-3,5);
119 | var x = random(-a,a);
120 | var y = random(-b,b);
121 | while(((x-xc)/a)*((x-xc)/a) + ((y-yc)/b)*((y-yc)/b) > 1){
122 | var x = random(-a,a);
123 | var y = random(-b,b);
124 | }
125 | fill(210,210,210);
126 | rect(xc+x,yc+y,rx,ry,10,10);
127 | fill(255,255,255);
128 | rect(xc+x+15,yc+y-15,rx,ry,10,10);
129 | }
130 | return [30,30,2*a-60,2*b-60];
131 | }
132 |
133 | register(marmsCloud, "Marms Cloud", "Henrique Martinez Rocamora");
134 |
135 | // Unicode Cloud by Sergio Fernández
136 | function unicodeCloud() {
137 | var size = floor(min(width, height * 2));
138 | textSize(size);
139 |
140 | var widthOfCloud = size;
141 | var heightOfCloud = widthOfCloud * 0.37;
142 | var textX = (width - widthOfCloud) / 2;
143 | var textY = height - (height - heightOfCloud) / 2;
144 | textAlign(LEFT, BASELINE);
145 | text("☁", textX, textY);
146 |
147 | return [
148 | textX + (widthOfCloud * 0.25),
149 | textY - (heightOfCloud * 0.7),
150 | widthOfCloud * 0.6,
151 | heightOfCloud * 0.6
152 | ];
153 | }
154 | register(unicodeCloud, "Unicode", "Sergio Fernández");
155 |
156 | function flatBottomCloud() {
157 | let radius = width / 4; // I don't really know where I messed up but for now just don't change the radius...
158 | let cloudWidth = width - radius - 100;
159 | let cloudHeight = height - radius - 100;
160 | let circleCount = cloudWidth / (radius*0.5);
161 |
162 | push();
163 | translate(width / 2, height / 1.75);
164 | ellipse(0,radius/4,cloudWidth,radius);
165 |
166 | for (let i = 0; i < circleCount; i++) {
167 | let angle = -PI / circleCount * i;
168 |
169 | let x = cloudWidth / 2 * cos(angle);
170 | let y = cloudHeight / 2 * sin(angle);
171 |
172 | ellipse(x, y, radius, radius);
173 | }
174 |
175 | noStroke();
176 | ellipse(0, -radius/5, cloudWidth+radius/2, cloudHeight+radius/10);
177 | pop();
178 |
179 | return [100, 200, width - 200, height - 400];
180 | }
181 |
182 | register(flatBottomCloud, "Flat Bottom", "Merijn_DH");
183 |
184 | function kazakhCloud(radius = 200, min = 8, max = 10) {
185 | // This function draws a cloud which margins are inside of a "circle" with
186 | // a given radius. The circle is not perfect, its boundaries may vary
187 | // according to the value offset. Number of "peak" points is determined via
188 | // min and max values.
189 | let points = [];
190 | let offset = radius / 5;
191 | let numPoints = Math.round(random(min, max));
192 | for (let i = 0; i < numPoints; i++) {
193 | // generating "peak" points of a cloud away from the center
194 | let angle = (TWO_PI / numPoints) * i;
195 | let away;
196 | while (true) {
197 | away = Math.round(random(radius) + offset);
198 | if (Math.abs(away - radius) <= offset) {
199 | break;
200 | }
201 | }
202 | let x = width / 2 + away * Math.cos(angle);
203 | let y = height / 2 - away * Math.sin(angle);
204 | points.push([x, y]);
205 | }
206 | noStroke();
207 | fill("#FFF");
208 | ellipse(width / 2, height / 2, 2.3*radius, 2.3*radius);
209 | for (let i = 0; i < points.length; i++) {
210 | // drawing arcs with the center inbetween every pair of points
211 | let center = [];
212 | let circleRadius;
213 | if (i == points.length - 1) {
214 | center = [(points[i][0] + points[0][0]) / 2, (points[i][1] + points[0][1]) / 2];
215 | circleRadius = dist(points[i][0], points[i][1], points[0][0], points[0][1]);
216 | } else {
217 | center = [(points[i][0] + points[i+1][0]) / 2, (points[i][1] + points[i+1][1]) / 2];
218 | circleRadius = dist(points[i][0], points[i][1], points[i+1][0], points[i+1][1]);
219 | }
220 | // finding slope and y-intercept for a line between center and point
221 | let mCircle = (center[1] - points[i][1]) / (center[0] - points[i][0]);
222 | let bCircle = center[1] - mCircle * center[0];
223 | let x1Origin = (0 - bCircle) / mCircle; // finding line's intercept with X-axis
224 | let x2Origin = center[0]; // another line is a projection of previous on X
225 | // finally getting the angle using found 2 lines and trigonometry
226 | let angle = Math.acos(dist(x2Origin, 0, x1Origin, 0) / dist(center[0], center[1], x1Origin, 0));
227 | // drawing arcs with right angle offset according to the placement of the center
228 | strokeWeight(10);
229 | stroke("#000");
230 | fill("#FFF");
231 | if (center[0] > width / 2 && center[1] < height / 2) {
232 | arc(center[0], center[1], circleRadius, circleRadius, PI+angle, angle);
233 | } else if (center[0] < width / 2 && center[1] < height / 2) {
234 | arc(center[0], center[1], circleRadius, circleRadius, PI-angle, -angle);
235 | } else if (center[0] < width / 2 && center[1] > height / 2) {
236 | arc(center[0], center[1], circleRadius, circleRadius, angle, PI+angle);
237 | } else if (center[0] > width / 2 && center[1] > height / 2) {
238 | arc(center[0], center[1], circleRadius, circleRadius, -angle, PI-angle);
239 | } else if (center[0] == width / 2 && center[1] < height / 2) {
240 | arc(center[0], center[1], circleRadius, circleRadius, PI, 0);
241 | } else if (center[0] == width / 2 && center[1] > height / 2) {
242 | arc(center[0], center[1], circleRadius, circleRadius, 0, PI);
243 | } else if (center[0] < width / 2 && center[1] == height / 2) {
244 | arc(center[0], center[1], circleRadius, circleRadius, HALF_PI, PI + HALF_PI);
245 | } else if (center[0] > width / 2 && center[1] == height / 2) {
246 | arc(center[0], center[1], circleRadius, circleRadius, PI + HALF_PI, HALF_PI);
247 | }
248 | }
249 | let rectSide = Math.round(Math.sqrt(2) * (radius - offset));
250 | return [width/2 - rectSide/2, height/2 - rectSide/2, radius+offset, radius+offset];
251 | }
252 |
253 | register(kazakhCloud, "Cloud from Kazakhstan", "Ilyas triple-o-zero");
254 |
255 | function fluffyCloud(){
256 | var cloudradius = 0.7*(width/2);
257 | var angle = PI/2;
258 | fill(255);
259 | while(angle<(2.5*PI)){
260 | ellipse(width/2+cos(angle)*cloudradius,height/2+sin(angle)*0.5*cloudradius,(width/2-sin(angle)*cloudradius)/3);
261 | angle += (width/2-sin(angle)*cloudradius)/(3.9*cloudradius);
262 | }
263 | noStroke();
264 | ellipse(width/2-4,height/2-cloudradius*0.075,cloudradius*2.4,cloudradius*1.24);
265 | stroke(0);
266 | return [120, 180, width - 240, height - 400];
267 | }
268 |
269 | register(fluffyCloud, "Fluffy", "egg303");
270 |
271 | //Draw a nice round cloud by Brandon Blaschke
272 | function proudRoundCloud() {
273 |
274 | //Amount of circles in the cloud
275 | let circleAmou = 15;
276 |
277 | //Radius for surrounding clouds
278 | let radius = 200;
279 |
280 | strokeWeight(5);
281 | fill(255);
282 |
283 | //Position and set up drawing
284 | push();
285 | angleMode(DEGREES);
286 | translate(width / 2, height / 2);
287 |
288 | //Make outer edge of cloud by going in a circle around the name
289 | for(let i = 0; i < circleAmou; i++) {
290 | let angle = map(i, 0, circleAmou, 0, 360);
291 | let x = 400 * cos(angle);
292 | let y = 250 * sin(angle);
293 | ellipse(x,y, radius, radius);
294 | }
295 |
296 | //Fill the inside with white circles to fill it
297 | noStroke();
298 | for(let i = 0; i < circleAmou; i++) {
299 | let angle = map(i, 0, circleAmou, 0, 360);
300 | let x = 200 * cos(angle);
301 | let y = 200 * sin(angle);
302 | ellipse(x,y, radius, radius);
303 | }
304 |
305 | //Fill the middle section
306 | ellipse(0,0,950, 550);
307 | pop();
308 |
309 | return [100, 100, width - 200, height - 200];
310 | }
311 |
312 | register(proudRoundCloud, "Proud Round Cloud", "Brandon Blaschke");
313 |
314 | // rndCloud
315 | // Generates a cloud, by drawing ellipses of random width and height on locus of a regular ellipse
316 | // Couldn't add a nice looking stroke to the cloud :( TODO: Add a beautiful stroke
317 | function rndCloud(){
318 | // Randomess - The main variable of the algorithm.
319 | // Randomness is inversely proportional to time taken to generate
320 | // Randomness is directly proportional to beauty (depends on viewers taste)
321 |
322 | const randomness = random(20,100);
323 | const r = width/2 - randomness;
324 | let x, y;
325 | push();
326 | translate(width / 2, height / 2);
327 | angleMode(DEGREES)
328 | noStroke();
329 | for(let i = 0; i <=360;)
330 | {
331 | x = r*cos(i);
332 | y = 0.5* r*sin(i);
333 | w = random(1,2) * randomness;
334 | h = random(1,2) * randomness;
335 | ellipse(x,y,w,h); //Draw the random ellipses
336 | ellipse(0,0,r*2,r); //Draw main ellipse
337 | i += randomness / 10;
338 | }
339 | pop();
340 | return [100, 100, width - 200, height - 200];
341 | }
342 |
343 | register(rndCloud, "RNDCloud", "Haider Ali Punjabi (@haideralipunjabi)")
344 |
345 | function cartoonCloud() {
346 | //Inspired by the cloud drawing from Processing Day organizer Taeyoon Choi
347 | function getRandMiniA() {
348 | return random(0, PI/24);
349 | }
350 | let radius = height/2.4;
351 | let angles = [0];
352 | angleMode(RADIANS);
353 |
354 | push();
355 | translate(width/2, height/2);
356 |
357 | //Fills the array with random angles that progressivly get bigger up until 2*PI
358 | //This creates the bigger and smaller cloud blobs, making it feel more natural
359 | let totalA = 0;
360 | while (totalA < 2*PI) {
361 | let a = random(PI/20, PI/6);
362 | if (totalA + a > 2*PI) {
363 | a = 2*PI - totalA;
364 | }
365 | totalA += a;
366 | angles.push(totalA);
367 | }
368 |
369 | //We first draw the cloud using begin/endShape() so we can fill() it
370 | noStroke();
371 | fill(255);
372 | beginShape();
373 | vertex(2*radius*cos(angles[0]), 2*radius*sin(angles[0]));
374 | for (let i = 0; i < angles.length; i++) {
375 | let a = angles[i];
376 | let deltaA = angles[(i+1)%angles.length] - a;
377 | if (deltaA < 0)deltaA+=2*PI;
378 | bezierVertex(
379 | 2*1.2*radius*cos(a + deltaA/3), 1.2*radius*sin(a + deltaA/3),
380 | 2*1.2*radius*cos(a + 2*deltaA/3), 1.2*radius*sin(a + 2*deltaA/3),
381 | 2*radius*cos(angles[(i+1)%angles.length]), radius*sin(angles[(i+1)%angles.length])
382 | );
383 | }
384 | endShape();
385 |
386 | //Now we draw the cloud 4 times, each time with a random offset
387 | //This gives the cloud a cartoony feeling
388 | stroke(0, 200);
389 | for (let l = 0; l < 4; l++) {
390 | for (let i = 0; i < angles.length; i++) {
391 | //Draw a bezier curve with a random stroke, a touch of alpha and some RNG
392 | let a = angles[i];
393 | let deltaA = angles[(i+1)%angles.length] - a;
394 | if (deltaA < 0){deltaA+=2*PI;}
395 | strokeWeight(random(10,14));
396 | bezier(
397 | 2*radius*cos(a), radius*sin(a),
398 | 2*1.2*radius*cos(a + deltaA/3- getRandMiniA()), 1.2*radius*sin(a + deltaA/3- getRandMiniA()),
399 | 2*1.2*radius*cos(a + 2*deltaA/3+ getRandMiniA()), 1.2*radius*sin(a + 2*deltaA/3+ getRandMiniA()),
400 | 2*radius*cos(angles[(i+1)%angles.length]), radius*sin(angles[(i+1)%angles.length])
401 | );
402 | }
403 | }
404 | pop();
405 | return [width/2 - 2*radius/1.4, height/2 - radius / 1.4, 4 * radius / 1.4, 2 * radius / 1.4];
406 | }
407 |
408 | register(cartoonCloud, "Cartoon cloud", "@JeBoyJurriaan");
409 |
410 | function unstableCloud() {
411 |
412 | // You can change:
413 | // sizeFactor (how big/small the cloud will be)
414 | // all colors
415 | // DEBUG (to see how it's made)
416 |
417 | // Utils
418 | const DEBUG = false
419 | const debugColor = (alpha=150) => color(random(255), random(255), random(255), alpha)
420 | const cloudColor = (alpha=255) => color(255, alpha)
421 | const shadowColor = (alpha=255) => color(20, alpha)
422 | const createCloud = (pos, d) => {
423 | return {pos: pos, d: d}
424 | }
425 | const drawCanvasBackground = () => {
426 | noStroke()
427 | fill(0,0,0,25)
428 | rect(0, 0, width, height)
429 | }
430 | const drawCloudBase = (pos, w, h) => {
431 | noStroke()
432 | DEBUG ? fill(debugColor()) : fill(cloudColor())
433 | rect(pos.x, pos.y, w, h)
434 | }
435 | const drawPuffyCloud = (cloud) => {
436 | noStroke()
437 | DEBUG ? fill(debugColor()) : fill(cloudColor())
438 | ellipse(cloud.pos.x, cloud.pos.y, cloud.d, cloud.d)
439 | }
440 |
441 | const drawShadowCloud = (cloud) => {
442 | noStroke()
443 | DEBUG ? fill(debugColor()) : fill(shadowColor())
444 | ellipse(cloud.pos.x, cloud.pos.y, cloud.d * shadowThickness, cloud.d * shadowThickness)
445 | }
446 |
447 | const getArcCenter = (A, B, C) => {
448 |
449 | // Mid-points AB and BC
450 | const midAB = A.copy().add(B).div(2)
451 | const midBC = B.copy().add(C).div(2)
452 |
453 | // Slopes AB and BC
454 | const slopeAB = (B.y-A.y)/(B.x-A.x)
455 | const slopeBC = (C.y-B.y)/(C.x-B.x)
456 |
457 | // Perpendicular lines runing through mid-points AB and BC
458 | const slopePerpAB = -Math.pow(slopeAB, -1)
459 | const slopePerpBC = -Math.pow(slopeBC, -1)
460 |
461 | // determine b to get linear equation standard form y = mx + b
462 | const bAB = midAB.y - slopePerpAB * midAB.x
463 | const bBC = midBC.y - slopePerpBC * midBC.x
464 |
465 | // get intersection point
466 | const x = (bBC - bAB)/(slopePerpAB - slopePerpBC)
467 | const y = slopePerpBC * x + bBC
468 |
469 | if(DEBUG) {
470 | stroke(255)
471 | strokeWeight(5)
472 | line(midAB.x, midAB.y, x, y)
473 | line(midBC.x, midBC.y, x, y)
474 | line(B.x, B.y, C.x, C.y)
475 | line(B.x, B.y, A.x, A.y)
476 | noStroke()
477 | fill(0, 200)
478 | ellipse(A.x, A.y, 20, 20)
479 | ellipse(B.x, B.y, 20, 20)
480 | ellipse(C.x, C.y, 20, 20)
481 | ellipse(x, y, 20, 20)
482 | }
483 |
484 | return createVector(x, y)
485 | }
486 |
487 | // Variable factores
488 | const sizeFactor = 1
489 | const rndBaseHeight = 250 + random(50)
490 | const rndArcCenterHeight = -25 + random(75)
491 | const nPuffyClouds = Math.round(6+random(1))
492 | const puffyCloudsBaseSize = 300 * sizeFactor
493 | const puffyCloudsSizeOffset = 100 * sizeFactor
494 | const shadowThickness = 1.05
495 |
496 | // Cloud base
497 | const baseWidth = 1100 * sizeFactor
498 | const baseHeight = rndBaseHeight * sizeFactor
499 | const baseCenter = createVector(width*.5, height*.6)
500 | const basePos = createVector(baseCenter.x - baseWidth *.5, baseCenter.y - baseHeight *.5)
501 |
502 | // Puffy clouds
503 | let puffyClouds = []
504 | const puffyDiameter = baseHeight
505 | const puffyRadius = puffyDiameter*.5
506 | const puffyPos = createVector(basePos.x, basePos.y + baseHeight - puffyRadius)
507 | const puffyLeft = createCloud(puffyPos, puffyDiameter)
508 | const puffyRight = createCloud(puffyPos.copy().add(baseWidth, 0), puffyDiameter)
509 | puffyClouds.push(puffyLeft)
510 | puffyClouds.push(puffyRight)
511 |
512 | // Create arc from 3 points
513 | const A = puffyLeft.pos.copy().sub(puffyRadius*.5, 0)
514 | const B = baseCenter.copy().sub(0, baseHeight*.5).sub(0, rndArcCenterHeight)
515 | const C = puffyRight.pos.copy().add(puffyRadius*.5, 0)
516 | const arcCenter = getArcCenter(A, B, C)
517 | const arcRadius = B.dist(arcCenter)
518 | const arcDiameter = arcRadius * 2
519 | const arcOffsetAngle = atan(-(C.y - arcCenter.y) / (C.x - arcCenter.x))
520 | const arcTotalAngle = PI - 2*arcOffsetAngle
521 | const arcAngleStep = arcTotalAngle/(nPuffyClouds-1)
522 |
523 | for(let i = 1; i < nPuffyClouds-1; i++) {
524 | const x = cos(i*(arcAngleStep)+arcOffsetAngle)*arcRadius
525 | const y = -sin(i*(arcAngleStep)+arcOffsetAngle)*arcRadius
526 | const sizeOffset = map(y, -sin(arcOffsetAngle) * arcRadius, -arcRadius, 0, puffyCloudsSizeOffset, true)
527 | const r = puffyCloudsBaseSize + random(sizeOffset)
528 | puffyClouds.push(createCloud(createVector(x, y).add(arcCenter), r))
529 | }
530 |
531 | // Draw
532 | if(DEBUG) {
533 | drawCanvasBackground()
534 | stroke(0)
535 | noFill()
536 | arc(arcCenter.x, arcCenter.y, arcDiameter, arcDiameter, PI+arcOffsetAngle, -arcOffsetAngle)
537 | }
538 | puffyClouds.forEach(drawShadowCloud)
539 | drawCloudBase(basePos, baseWidth, baseHeight)
540 | // line(basePos.x, basePos.y + baseHeigth, basePos.x + baseWidth, basePos.y + baseHeigth)
541 | puffyClouds.forEach(drawPuffyCloud)
542 | stroke(shadowColor())
543 | strokeWeight(shadowThickness * 5.5 * sizeFactor)
544 | line(basePos.x, basePos.y + baseHeight*1.013, basePos.x + baseWidth, basePos.y + baseHeight*1.013)
545 |
546 | return [basePos.x, basePos.y - baseHeight*.1, baseWidth, baseHeight]
547 | }
548 |
549 | register(unstableCloud, "A Cloud", "@unstablectrl")
550 |
551 | function someCloud(){
552 | angleMode(DEGREES);
553 | translate(width/2, height/2);
554 |
555 | let fullDeg = 360,
556 | sz = 2;
557 |
558 | noStroke();
559 | fill(255)
560 | arc(0, 0, 400 * sz, 310 * sz, 0, fullDeg)
561 |
562 | for(let i = 0;i <= fullDeg; i++){
563 | let s = 200 * sz * sin(i);
564 | let c = 150 * sz * cos(i);
565 | arc(s, c, random(100), random(100), 0, fullDeg);
566 | }
567 |
568 | return [-350, -200, width - 200, height -200];
569 | }
570 |
571 | register(someCloud, "Some Cloud", "Indmind");
572 |
573 | // arbitrary cloud by Hung
574 | function arbitraryCloud(){
575 | let cloud_x = 50;
576 | let cloud_y = 50;
577 | let cloud_width = width - cloud_x * 2;
578 | let cloud_height = height - cloud_y * 2;
579 |
580 | let cloud_center_size = {
581 | "width" : cloud_width - 300,
582 | "height" : cloud_height - 300
583 | };
584 |
585 | let cloud_center = {
586 | x: (width - cloud_center_size.width) / 2,
587 | y: (height - cloud_center_size.height) / 2
588 | };
589 | ellipseMode(CORNER);
590 | noStroke();
591 | // center area for drawing text
592 | ellipse(
593 | cloud_center.x,
594 | cloud_center.y,
595 | cloud_center_size.width,
596 | cloud_center_size.height
597 | );
598 | // generate random sub clouds
599 |
600 | // sub clouds infos
601 | let number_random_sub_clouds = 10;
602 | let smallest_sub_cloud_width = 200;
603 | let smallest_sub_cloud_height = 200;
604 |
605 | for(let i = 0; i < number_random_sub_clouds; i++){
606 | let rand_width = random(smallest_sub_cloud_width, cloud_width - 100);
607 | let rand_height = random(smallest_sub_cloud_height, cloud_height - 100);
608 | let rand_x = random(cloud_x + 10, cloud_width - rand_width);
609 | let rand_y = random(cloud_y + 10, cloud_height - rand_height);
610 | ellipse(rand_x, rand_y, rand_width, rand_height);
611 | }
612 | return [cloud_center.x, cloud_center.y, cloud_center_size.width, cloud_center_size.height];
613 | }
614 | register(arbitraryCloud, "Arbitrary cloud", "Hung Nguyen (fb.com/ZeroXCEH)");
615 |
616 | function shadowCloud() {
617 |
618 | // A puffy cloud with a shadow by Arjen Klaverstijn info@arjenklaverstijn.com
619 | // https://github.com/arjhun
620 |
621 | angleMode(DEGREES);
622 |
623 | let segments = 0,
624 | radius = 600,
625 | start = random(0, 360),
626 | end = start + 360,
627 | min = 20,
628 | max = 40,
629 | puff = max * 5,
630 | cPoints = [];
631 |
632 | for (let i = start; i < end;) {
633 |
634 | segments = random(min, max);
635 | //next segment
636 | let nextV = i + segments;
637 | // lets fill up the last segment with a reasonable one
638 | if (end - nextV < max - (max - min / 2)) nextV = end;
639 | //create coordinates for bezier segments
640 | cPoints.push(
641 | [radius * sin(i),
642 | radius / 3 * cos(i),
643 | (radius + puff) * sin(i),
644 | (radius / 3 + puff) * cos(i),
645 | (radius + puff) * sin(nextV),
646 | (radius / 3 + puff) * cos(nextV),
647 | radius * sin(nextV),
648 | radius / 3 * cos(nextV)
649 | ]);
650 | i += segments
651 | //if next vertex is at the end stop drawing
652 | if (nextV == end) break;
653 | }
654 |
655 | function drawCloud(offSet) {
656 | push();
657 | translate(width / 2+offSet, height / 2+offSet);
658 | beginShape();
659 | for (let c = 0; c < cPoints.length; c++) {
660 | vertex(cPoints[c][0] , cPoints[c][1] );
661 | bezierVertex(cPoints[c][2] , cPoints[c][3] , cPoints[c][4] , cPoints[c][5] , cPoints[c][6] , cPoints[c][7] );
662 | }
663 | endShape();
664 | pop();
665 | }
666 |
667 | //draw the actuall clouds
668 |
669 | fill(0); // random shadow
670 | drawCloud(random(20,100));
671 |
672 | fill(255);
673 | drawCloud(0);
674 |
675 | return [width/2-radius, height/2 -(radius/3), radius*2, (radius/3)*2];
676 | }
677 |
678 | register(shadowCloud, "Cloud with Shadow", "Arjen Klaverstijn (@aklaverstijn)");
679 |
680 | function CircularCloud() {
681 | // Draw big cloud parts
682 | fill(255, 255, 255, 90);
683 | for(let i = 0; i < 500; i++){
684 | fill(255, 255, 255, 50);
685 | //the bigger i; the more centered are the circles and the less likely they are outlined
686 | let offsetVec = p5.Vector.random2D();
687 | let scaleX = random(-600, 600) / (i * 0.001+1);
688 | let scaleY = random(-300, 300) / (i * 0.001+1);
689 | offsetVec.x *= scaleX;
690 | offsetVec.y *= scaleY;
691 | let outside = offsetVec.mag();
692 | if(random(700) < outside && random() > 0.7){
693 | strokeWeight(1);
694 | //fill(200, 0, 0);
695 | }
696 |
697 | else strokeWeight(0);
698 | ellipse(width/2 + offsetVec.x, height/2 + offsetVec.y, random(50, width/4));
699 | }
700 |
701 | // Draw small cloud parts
702 | fill(255, 255, 255, 90);
703 | for(let i = 0; i < 500; i++){
704 | fill(255, 255, 255, 50);
705 | let offsetVec = p5.Vector.random2D();
706 | let scaleX = random(-500, 500) / (i * 0.001+1);
707 | let scaleY = random(-250, 250) / (i * 0.001+1);
708 | offsetVec.x *= scaleX;
709 | offsetVec.y *= scaleY;
710 | let outside = offsetVec.mag();
711 | if(random(3000) < outside && random() > 0.7){
712 | strokeWeight(1);
713 | //fill(200, 0, 0);
714 | }
715 | else strokeWeight(0);
716 | ellipse(width/2 + offsetVec.x, height/2 + offsetVec.y, random(10, width/8));
717 | }
718 |
719 |
720 | return [100, 100, width - 200, height - 200];
721 | }
722 |
723 | register(CircularCloud, "CircularCloud", "lokmeinmatz / Matthias");
724 |
725 | function cumulus() {
726 | let cloud = [];
727 | const x = width / 2,
728 | y = height / 1.8,
729 | humps = round(random(3, 7)),
730 | diameter = width / humps,
731 | spacing = diameter / 2,
732 | mainHumpPos = 0.5, // 0 = left > 1 = right
733 | piRatio = HALF_PI / (humps / (1 / mainHumpPos));
734 |
735 | for (let i in [...Array(humps)]) {
736 | // Start with smaller "puffs", larger in the middle, end with small again
737 | let sine = 1 + sin(piRatio * i),
738 | variance = random(1, 0.7 / mainHumpPos) * sine,
739 | radius = spacing * variance,
740 | newX = width/2 - x / 2 + spacing / 2 + spacing * i; // Seriously? That much effort to move half to the left then continue spacing to the right?
741 | cloud.push([newX, y, radius]); // save the cloud so we can double draw, idk how else to do it
742 | }
743 |
744 | // draw black cloud with stroke
745 | cloud.forEach(puff => {
746 | strokeWeight(10);
747 | arc(puff[0], puff[1], puff[2], puff[2], PI, TAU, PIE);
748 | });
749 |
750 | // draw white cloud without stroke
751 | cloud.forEach(puff => {
752 | fill(255);
753 | strokeWeight(0);
754 | arc(puff[0], puff[1], puff[2], puff[2], PI, TAU, PIE);
755 | });
756 |
757 | return [x / 2, 0, x, height];
758 | }
759 | register(cumulus, "Cumulus", "Luke Flego");
760 |
761 | function arcClouds() {
762 | // draws arc
763 | function drawArc(c1, c2, c3) {
764 | // first and second circle intersection points
765 | let fs_int_points = circleIntersetc(c1.x, c1.y, c1.r,
766 | c2.x, c2.y, c2.r);
767 | // second and third circle intersection points
768 | let st_int_points = circleIntersetc(c2.x, c2.y, c2.r,
769 | c3.x, c3.y, c3.r);
770 | //
771 | let p0_x = fs_int_points[0];
772 | let p0_y = fs_int_points[1];
773 | let p1_x = st_int_points[0];
774 | let p1_y = st_int_points[1];
775 | //
776 | let v = createVector(1, 0);
777 | let v1 = createVector(p0_x - c2.x, p0_y - c2.y);
778 | let v2 = createVector(p1_x - c2.x, p1_y - c2.y);
779 | let startAngle = -angle(v1, v);
780 | let endAngle = -angle(v2, v);
781 | strokeWeight(3);
782 | stroke(0);
783 | arc(c2.x, c2.y, c2.r * 2, c2.r * 2, startAngle, endAngle);
784 | }
785 | // computes angle between 2 vectors, returns value between [0, 2*PI]
786 | function angle(v1, v2) {
787 | return Math.atan2(v1.x * v2.y - v1.y * v2.x, v1.x * v2.x + v1.y * v2.y);
788 | }
789 | // computes the intersection points between 2 circles
790 | function circleIntersetc(x0, y0, r0, x1, y1, r1) {
791 | //
792 | let d = dist(x0, y0, x1, y1);
793 | // distance between P0 and P2
794 | let a = (r0 * r0 - r1 * r1 + d * d) / (2 * d);
795 | let h = sqrt(r0 * r0 - a * a);
796 | //
797 | let x2 = x0 + a * (x1 - x0) / d;
798 | let y2 = y0 + a * (y1 - y0) / d;
799 | //
800 | let intp1_x = x2 + h * (y1 - y0) / d;
801 | let intp2_x = x2 - h * (y1 - y0) / d;
802 | let intp1_y = y2 - h * (x1 - x0) / d;
803 | let intp2_y = y2 + h * (x1 - x0) / d;
804 | //
805 | return [intp1_x, intp1_y, intp2_x, intp2_y];
806 | }
807 | noFill();
808 | translate(width / 2, height / 2);
809 | let r1 = 400;
810 | let r2 = 200;
811 | let increment = 0.5;
812 | let firstCircle, secondCircle, thirdCircle;
813 | let circles = [];
814 | // create circles
815 | for(let angle = 0;angle < 2 * PI;angle+=increment) {
816 | let x = r1 * cos(angle);
817 | let y = r2 * sin(angle);
818 | let rr = random(100, 150);
819 | circles.push({
820 | x : x,
821 | y : y,
822 | r : rr
823 | });
824 | }
825 | // draw arcs
826 | for(let j = 0;j < circles.length - 2;j++) {
827 | firstCircle = circles[j];
828 | secondCircle = circles[j + 1];
829 | thirdCircle = circles[j + 2];
830 | if(firstCircle && secondCircle && thirdCircle) {
831 | drawArc(firstCircle, secondCircle, thirdCircle);
832 | }
833 | }
834 | //
835 | firstCircle = circles[circles.length - 2];
836 | secondCircle = circles[circles.length - 1];
837 | thirdCircle = circles[0];
838 | drawArc(firstCircle, secondCircle, thirdCircle);
839 | //
840 | firstCircle = circles[circles.length - 1];
841 | secondCircle = circles[0];
842 | thirdCircle = circles[1];
843 | drawArc(firstCircle, secondCircle, thirdCircle);
844 | //
845 | return [-r1, -r2, 2 * r1, 2* r2];
846 | }
847 |
848 | register(arcClouds, "Arc Cloud", "edwin.straub");
849 |
850 | // created by georges Daou 29-sep-2017
851 | function randomSimpleCloud() {
852 |
853 |
854 | let minWidthSub = (5 * width) / 100;
855 | let maxWidthSub = (30 * width) / 100;
856 |
857 | let minHeightSub = (70 * height) / 100;
858 | let maxHeightSub = (85 * height) / 100;
859 |
860 |
861 | let cloudWidth = width - floor(random(minWidthSub, maxWidthSub)) - 100;
862 | let cloudHeight = height - floor(random(minHeightSub, maxHeightSub) - 100);
863 |
864 | push();
865 | translate(width / 2, height / 2);
866 |
867 | noStroke();
868 | fill(255);
869 |
870 | //base papa cloud
871 | ellipse(0, 0, cloudWidth, cloudHeight);
872 |
873 | angleMode(DEGREES);
874 |
875 | for (let angle = 0; angle < 360; angle += random(20, 30)) { //generating little cloudinette :)
876 |
877 | //choose right coordinates for the cloudinette not too close to the edge
878 |
879 | let x = ((cloudWidth / 2) * cos(angle));
880 |
881 | if (abs(x) > cloudWidth / 2 - cloudWidth / 6)
882 | continue;
883 |
884 | let y = (cloudHeight / 2) * sin(angle);
885 |
886 | //pushing the cloudinette a bit to the center for more realistic look
887 | if (y >= 0)
888 | y = random(y - 20, y);
889 | else
890 | y = random(y, y + 20);
891 |
892 | // finally choose width and height in relation of the papa cloud size
893 | ellipse(x, y, random(cloudWidth / 4, cloudWidth / 4 + 15), random(cloudHeight / 2, cloudHeight / 2 + 15));
894 | }
895 |
896 | pop();
897 | return [100, 100, width - 200, height - 200];
898 | }
899 | register(randomSimpleCloud, "Simple Random Cloud", "Georges Daou");
900 |
901 | // Puffy Cloud
902 | function puffyCloud(){
903 | const puffRadius = width/6;
904 | const mainRadius = width/2.5;
905 | let x, y;
906 | let stack = [];
907 | push();
908 | translate(width / 2, height / 2);
909 | angleMode(DEGREES)
910 | noStroke();
911 | fill(255, 255, 255);
912 | ellipse(0, 0, mainRadius*2, mainRadius);
913 | fill(0, 0, 0);
914 | for(let i = 0; i <=360;) {
915 | x = mainRadius * cos(i);
916 | y = 0.5 * mainRadius * sin(i);
917 | r = puffRadius * random(0.9, 1.5) * ((y+width) / width);
918 | ellipse(x, y, r, r);
919 | i += random(15, 25);
920 | stack.push({x: x, y: y, r: r});
921 | }
922 | fill(255, 255, 255);
923 | stack.forEach(function (puff) {
924 | let x = puff.x * .97;
925 | let y = puff.y * .97;
926 | let r = puff.r * .985;
927 | ellipse(x, y, r, r);
928 | });
929 | pop();
930 | return [100, 100, width - 200, height - 200];
931 | }
932 |
933 | register(puffyCloud, "Puffy Cloud", "Cary Stanley (@carystanley)")
934 |
935 | function bubblyCloud() {
936 | let RANGE = 30;
937 | let SMALLEST = 0.1;
938 | let SHADOW_A = Math.PI / 8 * 3;
939 | let SHADOW_I = 1.1;
940 | let SIDE = (height < width ? height : width)
941 |
942 | for(var i = 0; i <= RANGE; i++) {
943 | let dist = i * (1 - SMALLEST) * 2 / RANGE - 1 - SMALLEST;
944 | let diameter = SIDE * (1 - dist * dist) * 0.7;
945 | let shadow = i / RANGE * 255
946 |
947 | push();
948 |
949 | translate(width / 2 - diameter / 2 + random(diameter), height / 2 - diameter / 2 + random(diameter));
950 |
951 | fill(shadow / 10 + 228);
952 | noStroke();
953 | smooth();
954 |
955 | ellipse(0, 0, diameter - 1, diameter - 1);
956 |
957 | var start_a = SHADOW_A + 0.005 - Math.PI / 2;
958 | var stop_a = SHADOW_A - 0.005 + Math.PI / 2;
959 |
960 | fill(shadow / 10 + 200);
961 | arc(0, 0, diameter, diameter, start_a, stop_a, CHORD);
962 |
963 | let m_d = diameter * SHADOW_I;
964 | let ad = asin(diameter / m_d);
965 |
966 | start_a = SHADOW_A - ad;
967 | stop_a = SHADOW_A + ad;
968 |
969 | let r_d = sqrt(m_d * m_d - diameter * diameter) / 2
970 | let offset_x = -r_d * cos(SHADOW_A);
971 | let offset_y = -r_d * sin(SHADOW_A);
972 |
973 | fill(shadow / 10 + 228);
974 | arc(offset_x, offset_y, m_d, m_d, start_a, stop_a, CHORD);
975 |
976 | pop();
977 | }
978 | return [(width - SIDE) / 2, (height - SIDE) / 2, SIDE, SIDE, 80];
979 | }
980 | register(bubblyCloud, "Bubbly Cloud", "G4m3M4ni4c");
981 |
982 | function mcCloud() {
983 | noStroke();
984 |
985 | const w = width - width / 3;
986 | const h = w / 4;
987 | const dmin = w / 4;
988 | const dmax = w / 2;
989 | const offset = createVector((width - w) / 2, (height - h) / 2);
990 | const gray = 240;
991 |
992 | const getPosition = (i) => {
993 | if (i < w) return createVector(i, 0);
994 | if (i < w + h) return createVector(w, i - w);
995 | if (i < w * 2 + h) return createVector(i - (w + h), h);
996 | if (i < (w + h) * 2) return createVector(0, i - (w * 2 + h));
997 | return null;
998 | };
999 |
1000 | let i = random(dmax - dmin);
1001 | let pos;
1002 | while (pos = getPosition(i)) {
1003 | pos.add(offset);
1004 | var d = random(dmin, dmax);
1005 | for (let j = 0; j <= 20; j+=5) {
1006 | fill(gray, gray, gray, map(j, 0, 20, 100, 0));
1007 | ellipse(pos.x, pos.y + 50 + j, d);
1008 | }
1009 | fill(255, 255, 255);
1010 | ellipse(pos.x, pos.y, d);
1011 | i += d / 2;
1012 | }
1013 |
1014 | rect(offset.x, offset.y, w, h);
1015 |
1016 | return [offset.x, offset.y, w, h];
1017 | }
1018 | register(mcCloud, "Mc Cloud", "Rodolphe Peccatte");
1019 |
1020 | function drawBumpyCloud()
1021 | {
1022 | push();
1023 | strokeWeight(5);
1024 | translate(width / 2, height / 2);
1025 | angleMode(DEGREES);
1026 | let cloudWidth = width / 2;
1027 | let cloudHeight = height / 2;
1028 | let vertices = [];
1029 |
1030 | for (let i = random(5, 15); i < 360; i += random(20, 15))
1031 | {
1032 | vertices.push(
1033 | {
1034 | x: cos(i) * (cloudWidth / 2),
1035 | y: sin(i) * (cloudHeight / 2)
1036 | });
1037 | }
1038 | vertices.push(vertices[0]);
1039 | stroke(0);
1040 | fill(255);
1041 | for (let i = 0; i < vertices.length - 1; i++)
1042 | {
1043 | let p1 = vertices[i];
1044 | let p2 = vertices[i + 1];
1045 | let dx = p2.x - p1.x;
1046 | let dy = p2.y - p1.y;
1047 | let dst = sqrt(dx * dx + dy * dy);
1048 | ellipse((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, dst, dst);
1049 | }
1050 | noStroke();
1051 | fill(255);
1052 | ellipse(0, 0, cloudWidth, cloudHeight);
1053 | pop();
1054 | cloudWidth = cloudWidth * 4 / 5;
1055 | cloudHeight = cloudHeight * 4 / 5;
1056 |
1057 | return [(width - cloudWidth) / 2, (height - cloudHeight) / 2, cloudWidth, cloudHeight];
1058 | }
1059 |
1060 | register(drawBumpyCloud, "Bumpy Cloud", "Fir3will");
1061 |
1062 | function fluffyTriangle(){
1063 | const cw = width - (width / 5); // Cloud width
1064 | const side = round(random(1)); // What side the inside triangle goes to
1065 | const bottomY = (height/3)*2;
1066 | const topY = height/3;
1067 | const topX = (width/5) + (side*(cw/3)) + (noise(100)*(cw/3));
1068 | const bs = cw/15;
1069 | // Noise used here to get random values close to the middle of the used values
1070 | fill(255);
1071 |
1072 | // bottom
1073 | for(let x=width/5+random(bs); x currentY ? BS_RECT_TOP : BS_RECT_TOP_RIGHT);
1168 | }
1169 | }
1170 |
1171 | topRectList.push({
1172 | x: currentX,
1173 | y: currentY,
1174 | size: size,
1175 | type: type
1176 | });
1177 |
1178 | currentY = nextY;
1179 | currentX += size;
1180 | }
1181 |
1182 | // ++++++++++ generate last TOP ELEMENT
1183 | topRectList.push({
1184 | x: currentX,
1185 | y: currentY,
1186 | size: BS_CLOUD_WIDTH - currentX,
1187 | type: BS_RECT_TOP
1188 | });
1189 |
1190 | // ++++++++++ generate BOTTOM
1191 | currentX = 0;
1192 | currentY = BS_CLOUD_HEIGHT;
1193 | nextY = currentY;
1194 | type = 0;
1195 |
1196 | while(currentX < BS_CLOUD_WIDTH - BS_CLOUD_MAX_SIZE) {
1197 | size = Math.round(random() * BS_CLOUD_RANDOM_VALUE) + BS_CLOUD_MIN_SIZE;
1198 | nextY += Math.round(random() * size / 2.0 - (size / 4.0));
1199 |
1200 | if(currentX < BS_CLOUD_WIDTH / 2.0) {
1201 | type = (nextY <= currentY ? BS_RECT_BOTTOM : BS_RECT_BOTTOM_LEFT);
1202 | } else {
1203 | if(bottomRectList.length <= 0) {type = BS_RECT_BOTTOM;}
1204 | else {
1205 | let item = bottomRectList[bottomRectList.length - 1];
1206 | type = (item.y <= currentY ? BS_RECT_BOTTOM : BS_RECT_BOTTOM_RIGHT);
1207 | }
1208 | }
1209 |
1210 | bottomRectList.push({
1211 | x: currentX,
1212 | y: currentY,
1213 | size: size,
1214 | type: type
1215 | });
1216 |
1217 | currentY = nextY;
1218 | currentX += size;
1219 | }
1220 |
1221 | // ++++++++++ generate last BOTTOM ELEMENT
1222 | bottomRectList.push({
1223 | x: currentX,
1224 | y: currentY,
1225 | size: BS_CLOUD_WIDTH - currentX,
1226 | type: BS_RECT_BOTTOM
1227 | });
1228 |
1229 | // +++++++++++ generate LEFT
1230 | currentX = 0;
1231 | currentY = topRectList[0].y + topRectList[0].size;
1232 |
1233 | while(currentY < (bottomRectList[0].y - bottomRectList[0].size - BS_CLOUD_MAX_SIZE)) {
1234 | size = Math.round(random() * BS_CLOUD_RANDOM_VALUE) + BS_CLOUD_MIN_SIZE;
1235 |
1236 | type = BS_RECT_LEFT;
1237 |
1238 | leftRectList.push({
1239 | x: currentX - size,
1240 | y: currentY,
1241 | size: size,
1242 | type: type
1243 | });
1244 |
1245 | currentY += size;
1246 | }
1247 |
1248 | // +++++++++++ generate last LEFT ELEMENT
1249 | size = (bottomRectList[0].y - bottomRectList[0].size) - currentY;
1250 | leftRectList.push({
1251 | x: currentX - size,
1252 | y: currentY,
1253 | size: size,
1254 | type: BS_RECT_LEFT
1255 | });
1256 |
1257 | // +++++++++++ generate RIGHT
1258 | currentX = topRectList[topRectList.length - 1].x + topRectList[topRectList.length - 1].size;
1259 | currentY = topRectList[topRectList.length - 1].y + topRectList[topRectList.length - 1].size;
1260 |
1261 | while(currentY < (bottomRectList[bottomRectList.length - 1].y - BS_CLOUD_MAX_SIZE)) {
1262 | size = Math.round(random() * BS_CLOUD_RANDOM_VALUE) + BS_CLOUD_MIN_SIZE;
1263 | type = BS_RECT_RIGHT;
1264 |
1265 | rightRectList.push({
1266 | x: currentX,
1267 | y: currentY,
1268 | size: size,
1269 | type: type
1270 | });
1271 |
1272 | currentY += size;
1273 | }
1274 |
1275 | // +++++++++++ generate last RIGHT ELEMENT
1276 | size = Math.abs((bottomRectList[bottomRectList.length - 1].y) - currentY);
1277 | rightRectList.push({
1278 | x: currentX,
1279 | y: currentY,
1280 | size: size,
1281 | type: BS_RECT_RIGHT
1282 | });
1283 |
1284 |
1285 | // draw rects
1286 | beginShape();
1287 | for(let i in topRectList) {
1288 | let item = topRectList[i];
1289 | bs_drawRect(item.x, item.y, item.size, item.type);
1290 | }
1291 | for(let i in rightRectList) {
1292 | let item = rightRectList[i];
1293 | bs_drawRect(item.x, item.y, item.size, item.type);
1294 | }
1295 | for(let i = bottomRectList.length - 1; i >= 0; i--) {
1296 | let item = bottomRectList[i];
1297 | bs_drawRect(item.x, item.y, item.size, item.type);
1298 | }
1299 | for(let i = leftRectList.length - 1; i >= 0; i--) {
1300 | let item = leftRectList[i];
1301 | bs_drawRect(item.x, item.y, item.size, item.type);
1302 | }
1303 | endShape();
1304 | fill(255);
1305 |
1306 | function bs_drawRect(posX, posY, size, type) {
1307 | switch(type) {
1308 | case BS_RECT_LEFT:
1309 | vertex(posX + size, posY + size);
1310 | vertex(posX, posY + size);
1311 | vertex(posX, posY);
1312 | vertex(posX + size, posY);
1313 | break;
1314 | case BS_RECT_TOP_LEFT:
1315 | vertex(posX, posY + size);
1316 | vertex(posX, posY);
1317 | vertex(posX + size, posY);
1318 | break;
1319 | case BS_RECT_BOTTOM_LEFT:
1320 | vertex(posX + size, posY + size);
1321 | vertex(posX, posY + size);
1322 | vertex(posX, posY);
1323 | break;
1324 | case BS_RECT_TOP:
1325 | vertex(posX, posY + size);
1326 | vertex(posX, posY);
1327 | vertex(posX + size, posY);
1328 | vertex(posX + size, posY + size);
1329 | break;
1330 | case BS_RECT_BOTTOM:
1331 | vertex(posX + size, posY);
1332 | vertex(posX + size, posY + size);
1333 | vertex(posX, posY + size);
1334 | vertex(posX, posY);
1335 | break;
1336 | case BS_RECT_BOTTOM_RIGHT:
1337 | vertex(posX + size, posY);
1338 | vertex(posX + size, posY + size);
1339 | vertex(posX, posY + size);
1340 | break;
1341 | case BS_RECT_RIGHT:
1342 | vertex(posX, posY);
1343 | vertex(posX + size, posY);
1344 | vertex(posX + size, posY + size);
1345 | vertex(posX, posY + size);
1346 | break;
1347 | case BS_RECT_TOP_RIGHT:
1348 | vertex(posX, posY);
1349 | vertex(posX + size, posY);
1350 | vertex(posX + size, posY + size);
1351 | break;
1352 | default: break;
1353 | }
1354 | }
1355 |
1356 | return [BS_DRAW_RECT_OFFSET, BS_DRAW_RECT_OFFSET, BS_DRAW_RECT_WIDTH, BS_DRAW_RECT_HEIGHT];
1357 | }
1358 |
1359 | register(bitStoneRectCloud, "bit-stone rect cloud", "Kuno Zoltner (github: kzoltner)");
1360 |
1361 | function curveVertexCloud() {
1362 | let radius = width/5;
1363 | let points = floor(random(5)) + 10;
1364 | let cloud = [];
1365 |
1366 | for (let angle = 0; angle < TWO_PI-0.1; angle += TWO_PI/points) {
1367 | let x = 2 * radius * cos(angle) + random(-20, 20);
1368 | let y = radius * sin(angle) + random(-20, 20);
1369 |
1370 | cloud.push(createVector(x,y));
1371 | }
1372 |
1373 | cloud.push(cloud[0]);
1374 |
1375 | push();
1376 | translate(width/2, height/2);
1377 |
1378 | noFill();
1379 | stroke(0);
1380 | strokeWeight(20);
1381 |
1382 | for (let i = 0; i < cloud.length-1; i++) {
1383 | beginShape();
1384 | curveVertex(0, 0);
1385 | curveVertex(cloud[i].x, cloud[i].y);
1386 | curveVertex(cloud[i+1].x, cloud[i+1].y);
1387 | curveVertex(0, 0);
1388 | endShape();
1389 | }
1390 |
1391 | pop();
1392 |
1393 | return [width/2-radius*1.4, height/2-radius/2, width/2+radius*1.4, height/2+radius/2];
1394 | }
1395 |
1396 | register(curveVertexCloud, "curveVertex() Cloud", "xperion");
1397 |
1398 | function noCloud() {
1399 | var bg, p, p1, p2, p3, p4, p5, center;
1400 | function drawCloud(points) {
1401 | stroke(bg);
1402 | beginShape();
1403 | for (var i = 0; i < points.length; i++) {
1404 | vertex(points[i].x, points[i].y);
1405 | }
1406 | endShape(CLOSE);
1407 |
1408 | stroke(0);
1409 | p = points[0];
1410 | for (var i = 1; i < points.length; i++) {
1411 | drawCloudArc(p, points[i]);
1412 | p = points[i];
1413 | }
1414 |
1415 | line(points[0].x, points[0].y, points[points.length-1].x, points[points.length-1].y);
1416 | }
1417 |
1418 | function drawCloudArc(begin, end) {
1419 | function f(p,d) {
1420 | return p[d] - ((center[d] - p[d])/2);
1421 | }
1422 | center = {"x": width/2, "y": height/2};
1423 | bezier(begin.x, begin.y, f(begin, "x"), f(begin,"y")-200, f(end, "x"), f(end, "y")-200, end.x, end.y);
1424 | }
1425 |
1426 | function randomOffset(n) {
1427 | return random(n*2)-n;
1428 | }
1429 |
1430 | p1 = {"x":200, "y":height-300};
1431 | p2 = {"x":(width/4)+randomOffset(100), "y":240+randomOffset(50)};
1432 | p3 = {"x":width*2/4+randomOffset(100), "y":150+randomOffset(50)};
1433 | p4 = {"x":150+(width*3/4)+randomOffset(100), "y":270+randomOffset(50)};
1434 | p5 = {"x":width-200, "y":height-300};
1435 |
1436 | bg = 150;
1437 | fill(bg);
1438 | drawCloud([p1,p2,p3,p4,p5].map(function(e){return {"x":e.x+100,"y":e.y}}));
1439 | bg = 255;
1440 | fill(bg);
1441 | drawCloud([p1,p2,p3,p4,p5]);
1442 |
1443 | return [100, 100, width - 200, height - 200];
1444 | }
1445 | register(noCloud, "There is no cloud", "rnoennig");
1446 |
1447 | /**
1448 | * To draw a square cloud composed of other squares
1449 | */
1450 | function squareNotBlueCloud()
1451 | {
1452 |
1453 | push();
1454 | fill(255);
1455 | stroke(200);
1456 | rectMode(CENTER);
1457 |
1458 | var maxSquare = 60;
1459 |
1460 | // Function to draw n concentric squares from a center (x, y)
1461 | function putSquare(x, y, s, n) {
1462 |
1463 | for (var i = n - 1; i >= 0; --i) {
1464 |
1465 | rect(x, y, s * (i + 1), s * (i + 1));
1466 | }
1467 | }
1468 |
1469 | // Main body
1470 | var maxLen = floor(min(width, height) / 20);
1471 | putSquare((width / 4) + 3 * maxLen, height / 2, maxLen, 15);
1472 | putSquare((3 * width / 4) - 3 * maxLen, height / 2, maxLen, 15);
1473 |
1474 | // Sub clouds
1475 | for (var i = 0; i < maxSquare; ++i) {
1476 |
1477 | putSquare(
1478 | random((width / 4) - maxLen * 6, (3 * width / 4) + maxLen * 6),
1479 | random((height / 2) - maxLen * 8, (height / 2) + maxLen * 8),
1480 | maxLen,
1481 | floor(random(1, 6))
1482 | );
1483 | }
1484 |
1485 | pop();
1486 |
1487 | return [width / 2, height / 2, maxLen * 15, maxLen * 15, "77F"];
1488 | }
1489 |
1490 | register(squareNotBlueCloud, "Square Not Blue Cloud", "Juan Sebastian Robles");
1491 |
1492 | function CloudyCloud()
1493 | {
1494 | //I'm really sorry about this one xD
1495 | translate(width/2,height/2);
1496 | noStroke();
1497 | for(let i = 0; i < 30; i++)
1498 | ellipse(random(-130,130),random(-15,25),random(50,200));
1499 |
1500 | return [-130,-50,130*2,50*2];
1501 | }
1502 | register(CloudyCloud, "Radnomly Generated Cloud", "this.Zohir")
1503 |
1504 | function CloudyMcCloudson(){
1505 | for(var i = 0; i<15;i++){
1506 | noStroke();
1507 | ellipse(random(600,1400),random(200,450),random(300,400),random(300,400));
1508 | }
1509 | return [700, 200, 400,400];
1510 | }
1511 | register(CloudyMcCloudson, "Cloudy McCloudson", "Marius Bauer");
1512 |
1513 | function MaxTaylorCloud() {
1514 | let clouds = []
1515 | // Play with these to get the desired effect
1516 | const showBorder = true
1517 | const showTransparency = false;
1518 | const puffyNess = 40
1519 | const radius = 150
1520 |
1521 | for (let i = 0; i < puffyNess; i++) {
1522 | let x = width/2 + random(-200, 200)
1523 | let y = height/2 + random(-100, 100)
1524 | clouds.push({ x, y })
1525 |
1526 | if (!showBorder) { continue; }
1527 |
1528 | noFill()
1529 | strokeWeight(5)
1530 | stroke(0)
1531 | ellipse(x, y, radius, radius)
1532 | }
1533 |
1534 | for (let cloud of clouds) {
1535 | noStroke()
1536 | fill(255, 255, 255, (!showBorder && showTransparency) ? random(170, 255) : 255);
1537 | ellipse(cloud.x, cloud.y, radius, radius)
1538 | }
1539 |
1540 | return [width/2 - 150, height/2 - 50, 300, 100]
1541 | }
1542 |
1543 | register(MaxTaylorCloud, "Cloudy McCloudFace", "Max Taylor");
1544 |
1545 | // Koch snowflake-shaped cloud
1546 | function kochSnowCloud() {
1547 | stroke(0);
1548 | strokeWeight(2);
1549 | fill(255);
1550 |
1551 | let flake_size = width / 5;
1552 |
1553 | let pos = createVector((width - flake_size) / 2, 3 * height / 4);
1554 | let angle = 0;
1555 | let yscale = height / width;
1556 |
1557 | function move(r) {
1558 | pos.add(createVector(r * Math.cos(angle), r * Math.sin(angle) * yscale));
1559 | }
1560 |
1561 | beginShape();
1562 | for (let i = 0; i < 13; i++) {
1563 | koch(flake_size);
1564 | angle -= 2 * PI / 13;
1565 | }
1566 | endShape(CLOSE);
1567 |
1568 | function koch(r) {
1569 | if (r > 5) {
1570 | koch(r / 3);
1571 | angle += PI / 3;
1572 | koch(r / 3);
1573 | angle -= 2 * PI / 3;
1574 | koch(r / 3);
1575 | angle += PI / 3
1576 | koch(r / 3);
1577 | } else {
1578 | vertex(pos.x, pos.y);
1579 | move(r);
1580 | }
1581 | }
1582 |
1583 | return [(width - 3.5 * flake_size) / 2, height / 6, flake_size * 3.5, height / 3];
1584 | }
1585 |
1586 | register(kochSnowCloud, "Koch Snow-Cloud", "Kristian Wichmann");
1587 |
1588 | function AbdulCloud(){
1589 | const canvas = document.querySelector('#defaultCanvas0');
1590 | noStroke();
1591 | c = {h:parseInt(canvas.style.height.replace('px',''))/2, w:parseInt(canvas.style.width.replace('px',''))/2};
1592 | const numberOfElip = random(1,500)
1593 | for(var i = 0; i num*0.95) {
1674 | var percent = map(i, num*0.95, num, 0, 1);
1675 | n = lerp(n, rZero, percent);
1676 | }
1677 |
1678 | // Polar to Cartesian
1679 | // coordinate transformation
1680 | var x = width/2 + n * cos(a);
1681 | var y = height/2 + n * sin(a);
1682 |
1683 | vertex(x, y);
1684 |
1685 | xoff += 0.1;
1686 |
1687 | }
1688 | endShape(CLOSE);
1689 | }
1690 |
1691 | register(roundCloud, "Round Cloud", "Simon Tiger");
1692 |
1693 | function lightning_cloud(x=0, y=0){
1694 | noStroke();
1695 | for (let i = 0; i < 100; i++){
1696 | const r = random(100);
1697 | ellipse(x + random(-100, 100), y + random(50, 150), r, r);
1698 | }
1699 |
1700 |
1701 | const lightning = function(x, y, strokeweight, length, depth = 1){
1702 | if (length < 1) return;
1703 | const nextDepth = [];
1704 | const intensity = sqrt(depth) * 10;
1705 | push();
1706 | noiseSeed(random(100));
1707 | stroke(255, 255, 255);
1708 | strokeWeight(strokeweight);
1709 |
1710 | let xCurr, yCurr;
1711 | let xPrev = x, yPrev = y;
1712 | for (let offset = 0; offset < length; offset+=10){
1713 | xCurr = xPrev + map(noise(offset * 0.1), 0, 1, -1, 1) * intensity;
1714 | yCurr = y + offset
1715 | line(xPrev, yPrev, xCurr , yCurr);
1716 | xPrev = xCurr;
1717 | yPrev = yCurr;
1718 | nextDepth.push([xCurr, yCurr]);
1719 | }
1720 |
1721 | pop();
1722 |
1723 | nextDepth.forEach((e) => {
1724 | for (let i = 0; i < random(-100, 4); i++)
1725 | lightning(e[0], e[1], strokeweight * 0.5, length * 0.4, depth + 1);
1726 | })
1727 |
1728 | }
1729 |
1730 | lightning(x , y + 100 , 5, 500);
1731 | }
1732 |
1733 | register(lightning_cloud, "Lightning Cloud", "Eitan Porat")
1734 |
1735 | function trainCloud()
1736 | {
1737 | // Draw train.
1738 | push();
1739 |
1740 | // Position, scale, stroke weight.
1741 | translate(width - 420, height - 100);
1742 | scale(2, 2);
1743 | strokeWeight(3);
1744 |
1745 | // Front.
1746 | beginShape();
1747 | vertex(60, 40);
1748 | vertex(110, 40);
1749 | vertex(115, 55);
1750 | vertex(110, 70);
1751 | vertex(60, 70);
1752 | endShape(CLOSE);
1753 | strokeWeight(2);
1754 | line(90, 50, 90, 60);
1755 | line(95, 50, 95, 60);
1756 | line(100, 50, 100, 60);
1757 | strokeWeight(3);
1758 |
1759 | // Back.
1760 | beginShape();
1761 | vertex(0, 10);
1762 | vertex(70, 8);
1763 | vertex(65, 70);
1764 | vertex(10, 50);
1765 | endShape(CLOSE);
1766 |
1767 | // Top.
1768 | beginShape(QUADS);
1769 | vertex(85, 40);
1770 | vertex(80, 10);
1771 | vertex(110, 10);
1772 | vertex(105, 40);
1773 | vertex(75, 10);
1774 | vertex(70, 0);
1775 | vertex(120, 0);
1776 | vertex(115, 10);
1777 | endShape(CLOSE);
1778 |
1779 | // Bottom.
1780 | beginShape(QUADS);
1781 | vertex(60, 70);
1782 | vertex(110, 70);
1783 | vertex(110, 85);
1784 | vertex(50, 85);
1785 | vertex(95, 70);
1786 | vertex(110, 70);
1787 | vertex(125, 90);
1788 | vertex(100, 90);
1789 | endShape();
1790 |
1791 | // Outer wheels.
1792 | ellipse(35, 70, 60);
1793 | ellipse(80, 89, 20);
1794 |
1795 | // Inner wheels.
1796 | fill(0);
1797 | ellipse(35, 70, 10);
1798 | ellipse(80, 89, 5);
1799 | noFill();
1800 | pop();
1801 |
1802 | // Cloud drawing function.
1803 | function drawCloud(cloudRadius, stepAngle, rotationOffset) {
1804 | noStroke();
1805 | ellipse(0, 0, cloudRadius * 4, cloudRadius * 2);
1806 | stroke(0);
1807 | for (let angle = rotationOffset; angle < rotationOffset + 360; angle += stepAngle)
1808 | {
1809 | const x = cloudRadius * 2 * cos(angle);
1810 | const y = cloudRadius * sin(angle);
1811 | const radius = cloudRadius + random(cloudRadius * 0.2);
1812 | const rotation = atan2(-x, 2 * y) - 90;
1813 | const gapAngle = 360 - random(70, 90);
1814 | const startAngle = -gapAngle + rotation;
1815 | const endAngle = gapAngle + rotation;
1816 |
1817 | noStroke();
1818 | ellipse(x, y, radius * 2, radius * 2);
1819 | stroke(0);
1820 | arc(x, y, radius * 2, radius * 2, startAngle, endAngle);
1821 | }
1822 | }
1823 |
1824 | // Draw big cloud.
1825 | push();
1826 | angleMode(DEGREES);
1827 | translate(width / 2 - 80, height / 2 - 80);
1828 | scale(2, 2);
1829 | strokeWeight(3);
1830 |
1831 | const radius = 70;
1832 | drawCloud(radius, Math.floor(360 / random(6, 8)), random(360));
1833 | pop();
1834 |
1835 | // Draw small cloud.
1836 | push();
1837 | translate(width - 290, height - 190);
1838 | strokeWeight(3);
1839 | drawCloud(radius / 4, Math.floor(360 / random(6, 8)), random(360));
1840 | pop();
1841 |
1842 | // Return safe drawing area.
1843 | return [width / 2 - 80 - radius * 4, height / 2 - 80 - radius * 2, radius * 8, radius * 4];
1844 | }
1845 | register(trainCloud, "Train Cloud", "Nils Weber");
1846 |
1847 | function p5Cloud() {
1848 |
1849 | // words that are used to make cloud stroke
1850 | var words = [ "alpha", "blue", "brightness", "color", "green", "hue",
1851 | "lerpColor", "lightness", "red", "saturation", "background", "clear",
1852 | "colorMode", "fill", "noFill", "noStroke", "stroke", "arc",
1853 | "ellipse", "line", "point", "quad", "rect", "triangle",
1854 | "ellipseMode", "noSmooth", "rectMode", "smooth", "strokeCap", "strokeJoin",
1855 | "strokeWeight", "bezier", "bezierPoint", "bezierTangent", "curve", "curveTightness",
1856 | "curvePoint", "curveTangent", "beginContour", "beginShape", "bezierVertex", "curveVertex",
1857 | "endContour", "endShape", "quadraticVertex", "vertex", "loadModel", "model",
1858 | "plane", "box", "sphere", "cylinder", "cone", "ellipsoid",
1859 | "torus", "HALF_PI", "PI", "QUARTER_PI", "TAU", "TWO_PI",
1860 | "preload", "setup", "draw", "remove", "noLoop", "loop",
1861 | "push", "pop", "redraw", "print", "frameCount", "focused",
1862 | "cursor", "frameRate", "noCursor", "displayWidth", "displayHeight", "windowWidth",
1863 | "windowHeight", "windowResized", "width", "height", "fullscreen", "pixelDensity",
1864 | "displayDensity", "getURL", "getURLPath", "getURLParams", "p5.Element", "createCanvas",
1865 | "resizeCanvas", "noCanvas", "createGraphics", "blendMode", "applyMatrix", "resetMatrix",
1866 | "rotate", "rotateX", "rotateY", "rotateZ", "scale", "shearX",
1867 | "shearY", "translate", "p5.TypedDict", "p5.NumberDict", "append", "arrayCopy",
1868 | "concat", "reverse", "shorten", "shuffle", "sort", "splice",
1869 | "subset", "float", "int", "str", "boolean", "byte",
1870 | "char", "unchar", "hex", "unhex", "join", "match",
1871 | "matchAll", "nf", "nfc", "nfp", "nfs", "split",
1872 | "splitTokens", "trim", "deviceOrientation", "accelerationX", "accelerationY", "accelerationZ",
1873 | "pAccelerationX", "pAccelerationY", "pAccelerationZ", "rotationX", "rotationY", "rotationZ",
1874 | "pRotationX", "pRotationY", "pRotationZ", "setMoveThreshold", "setShakeThreshold", "deviceMoved",
1875 | "deviceTurned", "deviceShaken", "keyIsPressed", "key", "keyCode", "keyPressed",
1876 | "keyReleased", "keyTyped", "keyIsDown", "mouseX", "mouseY", "pmouseX",
1877 | "pmouseY", "winMouseX", "winMouseY", "pwinMouseX", "pwinMouseY", "mouseButton",
1878 | "mouseIsPressed", "mouseMoved", "mouseDragged", "mousePressed", "mouseReleased", "mouseClicked",
1879 | "doubleClicked", "mouseWheel", "touches", "touchStarted", "touchMoved", "touchEnded",
1880 | "createImage", "saveCanvas", "saveFrames", "p5.Image", "loadImage", "image",
1881 | "tint", "noTint", "imageMode", "pixels", "blend", "copy",
1882 | "filter", "get", "loadPixels", "set", "updatePixels", "loadJSON",
1883 | "loadStrings", "loadTable", "loadXML", "httpGet", "httpPost", "httpDo",
1884 | "save", "saveJSON", "saveStrings", "saveTable", "p5.Table", "p5.TableRow",
1885 | "p5.XML", "day", "hour", "minute", "millis", "month",
1886 | "second", "year", "createVector", "p5.Vector", "abs", "ceil",
1887 | "constrain", "dist", "exp", "floor", "lerp", "log",
1888 | "mag", "map", "max", "min", "norm", "pow",
1889 | "round", "sq", "sqrt", "noise", "noiseDetail", "noiseSeed",
1890 | "randomSeed", "random", "randomGaussian", "acos", "asin", "atan",
1891 | "atan2", "cos", "sin", "tan", "degrees", "radians",
1892 | "angleMode", "textAlign", "textLeading", "textSize", "textStyle", "textWidth",
1893 | "textAscent", "textDescent", "loadFont", "text", "textFont", "p5.Font",
1894 | "camera", "perspective", "ortho", "ambientLight", "directionalLight", "pointLight",
1895 | "loadShader", "shader", "normalMaterial", "texture", "ambientMaterial", "specularMaterial",
1896 | "p5.Texture", "p5.RendererGL", "p5.Shader"
1897 | ];
1898 |
1899 | // vertices of the cloud shape (calculated manually)
1900 | var cloudPoints = [
1901 | createVector(557, 592),
1902 | createVector(468, 464),
1903 | createVector(497, 318),
1904 | createVector(657, 228),
1905 | createVector(713, 86),
1906 | createVector(874, 26),
1907 | createVector(949, 54),
1908 | createVector(1104, 28),
1909 | createVector(1224, 109),
1910 | createVector(1255, 226),
1911 | createVector(1404, 275),
1912 | createVector(1467, 421),
1913 | createVector(1370, 592),
1914 | createVector(557, 592),
1915 | ]
1916 |
1917 | // function to draw text under angle
1918 | function angledText(textToDraw, x, y, angle) {
1919 | push();
1920 | translate(x,y);
1921 | rotate(-angle);
1922 | text(textToDraw, 0, 0);
1923 | pop();
1924 | }
1925 |
1926 | // used in getStringByLength to continue from the last cut position
1927 | var remainderString = "";
1928 | // function that returns randomly generated string containing words that
1929 | // has approximate length in pixels of argument
1930 | function getStringByLength(length) {
1931 | ret = remainderString;
1932 |
1933 | while(textWidth(ret) < length) {
1934 | word = words[int(random(words.length))];
1935 | ret += word + " ";
1936 | }
1937 |
1938 | remainderString = "";
1939 | while(textWidth(ret) > length) {
1940 | remainderString = ret.charAt(ret.length - 1) + remainderString;
1941 | ret = ret.substring(0, ret.length - 1);
1942 | }
1943 |
1944 | return ret;
1945 | }
1946 |
1947 | //save font and other settings
1948 | push();
1949 | // draw the cloud shape
1950 | strokeWeight(50);
1951 | stroke(255,255,255);
1952 | strokeJoin(ROUND);
1953 | beginShape();
1954 | for(var i = 0; i < cloudPoints.length; i++) {
1955 | vertex(cloudPoints[i].x, cloudPoints[i].y);
1956 | }
1957 | endShape(CLOSE);
1958 |
1959 | // draw the textual cloud stroke
1960 | textFont("monospace", 30);
1961 | textStyle(BOLD);
1962 | strokeWeight(0);
1963 | fill(0);
1964 | for(var i = 0; i < cloudPoints.length - 1; i++) {
1965 | var startingPoint = cloudPoints[i];
1966 | var endingPoint = cloudPoints[i+1];
1967 |
1968 | var distance = startingPoint.dist(endingPoint);
1969 | var angle = p5.Vector.sub(endingPoint, startingPoint).heading();
1970 |
1971 | // use negative angle because math and canvase use different coordinate system
1972 | angledText(getStringByLength(distance), startingPoint.x, startingPoint.y, -angle);
1973 | }
1974 | // restore font and other settings
1975 | pop();
1976 |
1977 | // write cloud title
1978 | var titleRect = [763, 106, 420, 224];
1979 | textSize(56);
1980 | textAlign(CENTER,TOP);
1981 | text("Processing\nCommunity Day", titleRect[0], titleRect[1], titleRect[2], titleRect[3]);
1982 |
1983 | // return rectangle for text (calculated manually)
1984 | return [563, 306, 805, 224];
1985 | }
1986 |
1987 | register(p5Cloud, "P5.js Cloud", "RedAnt333");
1988 |
1989 | // Let there be clouds :)
1990 | function letThereBeClouds(){
1991 | // Very classy.
1992 | class CloudNode{
1993 | constructor(_x, _y, _index){
1994 | this.pos = createVector(_x, _y);
1995 | this.size = noise(_index)*width/4;
1996 | }
1997 |
1998 | render(){
1999 | stroke(0);
2000 | strokeWeight(4);
2001 | fill(255,200);
2002 | ellipse(this.pos.x, this.pos.y, this.size, this.size * 0.618);
2003 | }
2004 |
2005 | }
2006 | var cloudNodes = [];
2007 |
2008 | for (let i = 0; i < 123; i++){
2009 |
2010 | let x = width/2 + random()*width/8;
2011 | let y = height/2 + random()*height/12;
2012 |
2013 | cloudNodes.push(new CloudNode(x, y, i));
2014 | cloudNodes[i].render();
2015 | }
2016 |
2017 | }
2018 |
2019 | register(letThereBeClouds, "Let There Be Clouds", "Red Hen dev");
2020 |
2021 |
2022 | function bumpCloud(){
2023 |
2024 | let posX = [];
2025 | let posY = [];
2026 |
2027 | let ROOT_TWO = sqrt(2);
2028 |
2029 | strokeWeight(7);
2030 | stroke(0);
2031 | noFill();
2032 |
2033 | let x, y, r1, r2;
2034 |
2035 | x = width/2;
2036 | y = height/2;
2037 | r1 = width*3/5; //horizontal radius of ellipse
2038 | r2 = width*3/10; //vertical radius of ellipse
2039 |
2040 | beginShape();
2041 |
2042 | for(let Oangle = 0; Oangle < TWO_PI; Oangle+=0.35){ //Oangle = outer angle
2043 | let r = random(.75,1);
2044 | for(let Iangle = 0; Iangle < TWO_PI; Iangle+=0.01){ //Iangle = inner angle
2045 | vertex(x + (r1/2 * r * cos(Oangle)) + (width/10 * r * cos(Iangle)), y + (r2/2 * r * sin(Oangle)) + (width/10 * r * sin(Iangle)));
2046 | posX.push(x + (r1/2 * r * cos(Oangle)) + (width/10 * r * cos(Iangle)));
2047 | posY.push(y + (r2/2 * r * sin(Oangle)) + (width/10 * r * sin(Iangle)));
2048 | }
2049 | }
2050 |
2051 | endShape();
2052 |
2053 | noStroke();
2054 | fill(255);
2055 |
2056 | beginShape();
2057 |
2058 | for(let n = 0; n < posX.length; n++){
2059 | vertex(posX[n],posY[n]);
2060 | }
2061 |
2062 | endShape();
2063 |
2064 | noStroke();
2065 |
2066 | ellipse(x, y, r1, r2);
2067 |
2068 | return([-(r1/ROOT_TWO/2)+x , -(r2/ROOT_TWO/2)+y , ROOT_TWO/2*r1 , ROOT_TWO/2*r2]);
2069 |
2070 | }
2071 |
2072 | register(bumpCloud, "bumpCloud", "Xalkor");
2073 |
2074 | function britishCloud()
2075 | {
2076 | h = height/3;
2077 | w = width/2;
2078 | position = createVector(width/2, height/2);
2079 | numberOfFluffies = 15;
2080 |
2081 | angleMode(DEGREES);
2082 | // First draw the main inner ellipse;
2083 | push();
2084 | fill(255);
2085 | stroke(255);
2086 | ellipseMode(CENTER);
2087 | // Draw the outer "fluffy" bits/
2088 | for (let i = 0; i < numberOfFluffies; i++)
2089 | {
2090 | angle = 360/numberOfFluffies * i;
2091 | pX = position.x + ((w/2) * cos(angle));
2092 | pY = position.y + ((h/2) * sin(angle));
2093 | r = random(width/22, width/15);
2094 | if (pY > position.y)
2095 | {
2096 | push();
2097 | stroke(200,200,200);
2098 | fill(210,210,210);
2099 | ellipse(pX-(h/15), pY+(h/15), r*2, r*2);
2100 | pop();
2101 | }
2102 | ellipse(pX, pY, r*2, r*2);
2103 | }
2104 |
2105 | // Now draw some weather!!!!!!
2106 | type = int(random(1, 4));
2107 | switch(type)
2108 | {
2109 | case 1: // Lightening!!!
2110 | for(let i = 1; i <= 3; i++)
2111 | {
2112 | //bX = (this.position.x - this.w/2 * 0.8) + (this.w/3*0.8)*i;
2113 | bX = position.x + ((w/2) * cos((i*45)));
2114 | bY = position.y + ((h/2) * sin((i*45)));
2115 | bScale = random(h/250, h/150);
2116 | dir = int(random(0, 2));
2117 | if (dir === 0)
2118 | bDir = -1;
2119 | else
2120 | bDir = 1;
2121 | col = random(210, 255);
2122 | var bColour = color(160,210,col,200);
2123 | drawBolt(bX, bY, bScale, bDir, bColour);
2124 | }
2125 | break;
2126 |
2127 | case 2: // Rain!!!
2128 | push();
2129 | for(let i = 1; i <= 10; i++)
2130 | {
2131 | rX = (position.x + (w/25) + ((w/2+(w/12)) * cos(45 + i * 9)));
2132 | rY = (position.y + ((h/2-(h/12)) * sin(50)));
2133 | col = random(100, 255);
2134 | rColour = color(10,65,col,180);
2135 | stroke(rColour);
2136 | strokeWeight(h/12);
2137 | strokeCap(ROUND);
2138 | push();
2139 | translate(rX, rY);
2140 | rotate(20);
2141 | line(0, 0, 0, (h*0.66)+(i%2*(h/6)));
2142 | pop();
2143 | }
2144 | pop();
2145 | break;
2146 |
2147 | case 3: // Snow!!!
2148 | push();
2149 | for(let i = 1; i <= 5; i++)
2150 | {
2151 | sX = (position.x + (w/25) + ((w/2+(w/12)) * cos(45 + i * 18)));
2152 | sY = (position.y + (w/12) + ((h/2) * sin(50)));
2153 | drawSnowflake(sX, sY+(w/12));
2154 | }
2155 | pop();
2156 |
2157 | default:
2158 | break;
2159 | }
2160 | // Now fill the middle with white.
2161 | ellipse(position.x, position.y, w, h);
2162 | pop();
2163 |
2164 | return [position.x - w/2, position.y - h/2, w, h];
2165 |
2166 | function drawBolt(startX, startY, scl, direction, colour)
2167 | {
2168 | push();
2169 | fill(colour);
2170 | noStroke();
2171 | translate(startX, startY);
2172 | scale(scl);
2173 | quad(0*direction, 0,
2174 | 35*direction, 10,
2175 | 15*direction, 110,
2176 | 0*direction, 75);
2177 | quad(0*direction, 75,
2178 | 15*direction, 110,
2179 | -15*direction, 95,
2180 | -45*direction, 60);
2181 | triangle(-45*direction, 60,
2182 | -15*direction, 95,
2183 | -20*direction, 190);
2184 | pop();
2185 | }
2186 |
2187 | function drawSnowflake(centreX, centreY)
2188 | {
2189 | push();
2190 | stroke(255);
2191 | strokeWeight(w/250);
2192 | strokeCap(ROUND);
2193 | translate(centreX, centreY);
2194 | for (let flake = 0; flake < 3; flake++)
2195 | {
2196 | push();
2197 | scale(random(h/450, h/300));
2198 | translate(0, 0 + flake*(h/4));
2199 | rotate(random(0,59));
2200 | for (let branch = 0; branch < 6; branch++)
2201 | {
2202 | // Draw a branch, and then rotate by 60 degrees.
2203 | line(0, 0, 0, 50);
2204 | line(0, 20, 7, 20)
2205 | line(0, 20, -7, 20);
2206 | line(0, 30, 15, 37);
2207 | line(0, 30, -15, 37);
2208 | line(0, 40, 10, 45);
2209 | line(0, 40, -10, 45);
2210 | rotate(60);
2211 | }
2212 | pop();
2213 | }
2214 | pop();
2215 | }
2216 | }
2217 |
2218 | register(britishCloud, "British Cloud", "Jools");
2219 |
2220 | function EllipseNameTag(){
2221 |
2222 | //Create ellipse background which Cloud will rest on
2223 | fill(122, 182, 250) //Color of background
2224 | stroke(255)
2225 | strokeWeight(14)
2226 | ellipse(width/2, height/2, width/2, height/2.5);
2227 |
2228 | //Create cloud shadow
2229 | const m = random(25,50)
2230 | fill(255, 50)
2231 | noStroke()
2232 | for (var i = 0; i < m; i++){
2233 | ellipse(random(width/3,2*width/3),random((window.height/2) + window.height/10,(window.height/2) + window.height/8),random(60,100),random(30,50));
2234 | }
2235 |
2236 | //Create Cloud
2237 | fill(255)
2238 | const n = random(150,250)
2239 | for(var i = 0; i b
2403 | if( (angle >= 45 && angle <= 135) || (angle >= 225 && angle <= 315) )
2404 | { ellipse(x, y, a/8, a/8); }
2405 | else if( (angle >= 135 && angle <= 150) || ( angle >= 210 && angle <= 225 )
2406 | || (angle >= 315 && angle <= 330) || ( angle >= 30 && angle <= 45 ) )
2407 | { ellipse(x, y, a/10, a/10); }
2408 | else
2409 | { ellipse(x, y, a/13, a/13); }
2410 | }
2411 |
2412 | // draw larger ellipse with no border over smaller circles
2413 | // large ellipse will "erase" inner halves of smaller circles
2414 | stroke(255);
2415 | ellipse(0, 0, a, b);
2416 | }
2417 |
2418 | register(simpleCloud, "Simple Cloud", "GreenMoonArt");
2419 |
2420 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CommunityClouds
6 |
7 |
8 |
9 |
10 |
24 |
31 |
32 | Download SVG
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/print/extra_data.js:
--------------------------------------------------------------------------------
1 | var needs_stroke_added = [
2 | 2,
3 | 3,
4 | 8,
5 | 11,
6 | 12,
7 | 17,
8 | 19,
9 | 20,
10 | 27,
11 | 28,
12 | 31,
13 | 32,
14 | 33,
15 | 34,
16 | 39,
17 | 40
18 | ];
19 |
20 | var custom_size = {
21 | 35: 800
22 | }
23 |
--------------------------------------------------------------------------------
/print/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CommunityClouds
6 |
7 |
8 |
9 |
41 |
42 |
43 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/print/print.js:
--------------------------------------------------------------------------------
1 | let canvas;
2 | let canvasSvg;
3 | let generators = [];
4 |
5 | let currentSvg;
6 | let container;
7 | let generatorSelect;
8 | let sizeAdjust;
9 | let backgroundSelect;
10 | let addToPage;
11 | let addOneOfEach;
12 |
13 | let currentPage;
14 | let pageContainer;
15 |
16 | const outputWidth = 1200;
17 | const outputHeight = 900;
18 |
19 | function setup() {
20 | container = document.getElementById('svg-contain');
21 | sizeAdjust = document.getElementById('size-adjust');
22 | generatorSelect = document.getElementById('generator');
23 | backgroundSelect = document.getElementById('background');
24 | pageContainer = document.getElementById('pages');
25 | addToPage = document.getElementById('add-to-page');
26 | addOneOfEach = document.getElementById('add-one-of-each');
27 |
28 | currentPage = new_page();
29 |
30 | let scale = 0.1 + sizeAdjust.value / 100;
31 | canvas = createCanvas(1200 * scale, 900 * scale);
32 | canvas.parent("sketch-contain");
33 | noLoop();
34 |
35 | sizeAdjust.onchange = function() {
36 | let scale = 0.1 + sizeAdjust.value / 100;
37 | resizeCanvas(1200 * scale, 900 * scale);
38 | }
39 |
40 | generators.forEach(function(gen, i) {
41 | let elem = document.createElement('option');
42 | elem.value = i;
43 | elem.innerHTML = gen.name;
44 | generatorSelect.appendChild(elem);
45 | });
46 |
47 | generatorSelect.onchange = redraw;
48 |
49 | container.className = backgroundSelect.value;
50 | backgroundSelect.onchange = function() {
51 | container.className = backgroundSelect.value;
52 | }
53 |
54 | addToPage.onclick = add_to_page;
55 |
56 | addOneOfEach.onclick = function() {
57 | generators.forEach(function(gen, i) {
58 | generatorSelect.value = i;
59 | if(custom_size[i]) {
60 | resizeCanvas(custom_size[i], custom_size[i] / 4 * 3);
61 | } else {
62 | resizeCanvas(1200, 900);
63 | }
64 | add_to_page();
65 | });
66 | }
67 | }
68 |
69 | function draw() {
70 | canvasSvg = new C2S(width, height);
71 | canvas.drawingContext = canvasSvg;
72 | // Establish our default cloud drawing paremeters.
73 | rectMode(CORNER);
74 | ellipseMode(CENTER);
75 | angleMode(RADIANS);
76 | strokeWeight(10);
77 | // These are cached, so need to be reset
78 | stroke("#FFF");
79 | fill("#000");
80 | stroke("#000");
81 | fill("#FFF");
82 | var idx = +generatorSelect.value;
83 | gen = generators[idx];
84 | console.log(idx, gen);
85 | gen.fn();
86 |
87 | var xmlns = "http://www.w3.org/2000/svg";
88 | currentSvg = canvasSvg.getSvg();
89 | currentSvg.setAttribute('width', outputWidth);
90 | currentSvg.setAttribute('height', outputHeight);
91 | scale_svg(currentSvg, true);
92 | currentSvg.setAttribute('viewBox', `0 0 ${outputWidth} ${outputHeight}`);
93 | var g = currentSvg.lastChild;
94 | currentSvg.removeChild(g);
95 | var container_g = document.createElementNS(xmlns, 'g');
96 | container_g.appendChild(g);
97 | if(needs_stroke_added.indexOf(idx) > -1) {
98 | container_g.appendChild(g.cloneNode(true));
99 | alter_stroke(20, g);
100 | }
101 | currentSvg.appendChild(container_g);
102 |
103 | while(container.lastChild) {
104 | container.removeChild(container.lastChild);
105 | }
106 | container.appendChild(currentSvg);
107 | }
108 |
109 |
110 | function scale_svg(svg, append, margin) {
111 | if(append) {
112 | document.body.appendChild(svg);
113 | }
114 | margin = 50 || margin;
115 | var clientBounds = svg.getBoundingClientRect();
116 | var internalBounds = svg.lastChild.getBoundingClientRect();
117 | console.log(clientBounds, internalBounds);
118 | var x = clientBounds.x - internalBounds.x + margin;
119 | var y = clientBounds.y - internalBounds.y + margin;
120 | var scaleX = clientBounds.width / (internalBounds.width + 2 * margin);
121 | var scaleY = clientBounds.height / (internalBounds.height + 2 * margin);
122 | var scale = min(scaleX, scaleY);
123 | var original = svg.lastChild.getAttribute('transform') || '';
124 | var transform = `scale(${scale}, ${scale}) translate(${x}, ${y}) ${original}`;
125 | console.log(scaleX, scaleY, scale);
126 | console.log(transform);
127 | svg.lastChild.setAttribute('transform', transform);
128 | if(append) {
129 | document.body.removeChild(svg);
130 | }
131 | }
132 |
133 | function alter_stroke(size, elem) {
134 | if(elem.transform) {
135 | for(let i = 0; i < elem.transform.baseVal.length; i++) {
136 | let transform = elem.transform.baseVal.getItem(i);
137 | if(transform.type === SVGTransform.SVG_TRANSFORM_SCALE) {
138 | let scale_mult = min(transform.matrix.a, transform.matrix.d);
139 | size /= scale_mult;
140 | console.log(transform);
141 | }
142 | }
143 | }
144 | let color = elem.getAttribute('stroke');
145 | let width = elem.getAttribute('stroke-width') || 0;
146 | width = +width;
147 | color = "#000";
148 | width += size;
149 | elem.setAttribute('stroke', color);
150 | elem.setAttribute('stroke-width', width);
151 | for(child of elem.children) {
152 | alter_stroke(size, child);
153 | }
154 | }
155 |
156 | function new_page() {
157 | let template = document.getElementById('page-template').cloneNode(true);
158 | template.id = "";
159 | let anchor = document.createElement('a');
160 | anchor.target = "_blank";
161 | anchor.appendChild(template);
162 | pageContainer.appendChild(anchor);
163 | let page = {
164 | a: anchor,
165 | elements: 0,
166 | svg: template,
167 | };
168 | update_link(page);
169 | return page;
170 | }
171 |
172 | function update_link(page) {
173 | let blob = new Blob([page.svg.outerHTML], {type:"image/svg+xml;charset=utf-8"});
174 | let svgUrl = URL.createObjectURL(blob);
175 | page.a.href = svgUrl;
176 | }
177 |
178 | function add_to_page() {
179 | let id = currentPage.elements;
180 | let offsetX = (id % 2) * outputWidth + 75;
181 | let offsetY = Math.floor(id / 2) * outputHeight + 300;
182 | let newPart = currentSvg.lastChild.cloneNode(true);
183 | currentPage.svg.appendChild(newPart);
184 | newPart.setAttribute('transform', `translate(${offsetX}, ${offsetY})`);
185 | update_link(currentPage);
186 | currentPage.elements += 1;
187 | if(currentPage.elements === 6) {
188 | currentPage = new_page();
189 | }
190 | redraw();
191 | }
192 |
193 | // Register a new cloud generator.
194 | function register(fn, name, creator) {
195 | generators.push({
196 | fn: fn,
197 | name: name,
198 | creator: creator
199 | });
200 | }
201 |
--------------------------------------------------------------------------------
/sketch.js:
--------------------------------------------------------------------------------
1 | let nameInput,
2 | selectionInput,
3 | canvas,
4 | generators = [],
5 | generator,
6 | bounds,
7 | formContainer = document.querySelectorAll(".form-contain")[0],
8 | titleElement = document.getElementById("attrib-title"),
9 | authorElement = document.getElementById("author-name"),
10 | backgroundColor = "#77B5FE",
11 | download = document.getElementById("download"),
12 | canvasSvg,
13 | theSeed;
14 |
15 | // Resizes the canvas to match the CSS
16 | function resize() {
17 | let parStyle = window.getComputedStyle(canvas.elt.parentNode),
18 | cWidth = parseInt(parStyle.width),
19 | cHeight = parseInt(parStyle.height);
20 | resizeCanvas(cWidth, cHeight, true);
21 | }
22 |
23 | // When the window resizes
24 | function windowResized() {
25 | resize();
26 | redraw();
27 | }
28 |
29 | function keyReleased() {
30 | if (keyCode == UP_ARROW || keyCode == LEFT_ARROW) {
31 | selectionInput.previousItem();
32 | } else if (keyCode == DOWN_ARROW || keyCode == RIGHT_ARROW) {
33 | selectionInput.nextItem();
34 | }
35 | return false;
36 | }
37 |
38 | // On setup
39 | function setup() {
40 | // Default canvas size
41 | canvas = createCanvas(window.innerWidth, window.innerHeight);
42 | canvas.parent("sketch-contain");
43 | // When clicked
44 | canvas.elt.addEventListener("click", redraw);
45 | noLoop();
46 | resize();
47 |
48 | // Create list of selectable items
49 | // Begin selectable options object
50 | let selectOptions = {
51 | "random": {
52 | value : "Random",
53 | group : "_default", // Added underscore to sort before "community"
54 | default : true /** Group names should be used solely
55 | * to differentiate visual groups.
56 | * the default property allows users to
57 | * set a default, but keep it inline
58 | * with whichever group they're using.
59 | */
60 | }
61 | };
62 | // Finish populating selectOptions
63 | generators.forEach((n, i) => {
64 | selectOptions[n.name.toLowerCase()] = {
65 | value: n.name,
66 | group: "community"
67 | };
68 | });
69 | // Generate selector
70 | selectionInput = new MaterialSelect(selectOptions, "", true, redraw);
71 | // Add to clouds form
72 | select("#clouds-form-generator").elt.appendChild(selectionInput.nodesRef);
73 |
74 | // Material Design input field
75 | nameInput = new MaterialText("", "", "", true, "user_name", "Name", "");
76 | // Add to clouds form
77 | select("#clouds-form-options").elt.appendChild(nameInput.nodesRef);
78 | // Listen for value changes to redraw()
79 | nameInput.inputNode.addEventListener("input", redraw);
80 |
81 | }
82 |
83 | function updateBg(color) {
84 | backgroundColor = color.toHEXString();
85 | redraw();
86 | }
87 |
88 | function handleDrawing(){
89 | push();
90 |
91 | document.getElementsByTagName("body")[0].style.background = backgroundColor;
92 | background(backgroundColor);
93 |
94 | scale(.7);
95 | translate(width * .2, height * .2);
96 |
97 | // Establish our default cloud drawing paremeters.
98 | rectMode(CORNER);
99 | ellipseMode(CENTER);
100 | angleMode(RADIANS);
101 | strokeWeight(10);
102 | stroke("#000");
103 | fill("#FFF");
104 | // Render the chosen cloud and
105 | bounds = generator.fn();
106 |
107 | if (bounds) {
108 | // Reset styles for the text
109 | fill(bounds.length > 4 ? bounds[4] : "#000");
110 | strokeWeight(0);
111 | textSize(16);
112 | textAlign(CENTER, CENTER);
113 |
114 | textSize(100);
115 | // Output the name (Hopefully within the bounds)
116 | let theName = nameInput.validInput ? nameInput.validInput : "Example Name";
117 | text(theName, bounds[0], bounds[1], bounds[2], bounds[3]);
118 | } else {
119 | console.log(generator.name + " by " + generator.creator + ", did not return bounds.")
120 | }
121 | // Describe which design
122 | titleElement.innerHTML = generator.name;
123 | authorElement.innerHTML = generator.creator;
124 |
125 | pop();
126 | }
127 |
128 | function genRandomSeed(min, max) {
129 | return Math.random() * (max - min) + min;
130 | }
131 |
132 | function setSvgDownload(e){
133 | let tmpContext = canvas.drawingContext;
134 |
135 | let canStyleWidth = parseInt(canvas.elt.style.width),
136 | canStyleHeight = parseInt(canvas.elt.style.height);
137 |
138 | canvasSvg = new C2S(canStyleWidth, canStyleHeight);
139 | canvas.drawingContext = canvasSvg;
140 |
141 | randomSeed(theSeed);
142 | handleDrawing();
143 | let theSVG = canvasSvg.getSerializedSvg(true),
144 | svgBlob = new Blob([theSVG], {type:"image/svg+xml;charset=utf-8"}),
145 | svgUrl = URL.createObjectURL(svgBlob);
146 |
147 | download.setAttribute("href", svgUrl);
148 | canvas.drawingContext = tmpContext;
149 | }
150 |
151 | function draw() {
152 |
153 | download.removeEventListener("mousedown", setSvgDownload);
154 |
155 | theSeed = genRandomSeed(1, 100);
156 |
157 | if (selectionInput.curOpt !== 'random') {
158 | // Get generator chosen
159 | generator = generators[selectionInput.PresortIndex - 1];
160 | } else {
161 | // Chose a random generator
162 | generator = random(generators);
163 |
164 | }
165 |
166 | randomSeed(theSeed);
167 | noiseSeed(theSeed);
168 | handleDrawing();
169 |
170 | download.setAttribute("download", generator.name.split(' ').join('_') + ".svg");
171 |
172 | download.addEventListener("mousedown", setSvgDownload);
173 |
174 | randomSeed();
175 | noiseSeed();
176 |
177 | }
178 |
179 | // Register a new cloud generator.
180 | function register(fn, name, creator) {
181 | generators.push({
182 | fn: fn,
183 | name: name,
184 | creator: creator
185 | });
186 | }
187 |
--------------------------------------------------------------------------------