This repository has been archived by the owner on Jan 11, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spiro.html
233 lines (193 loc) · 8.71 KB
/
spiro.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Creating a Spirograph</title>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!-- Google fonts -->
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400' rel='stylesheet' type='text/css'>
<!-- Pym.js - iframe height handler for the Blog -->
<script src="pym.min.js"></script>
<!-- jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<style>
body {
font-family: 'Open Sans', sans-serif;
font-size: 12px;
font-weight: 400;
fill: #575757;
text-align: center;
background: #101420;
}
.spirograph {
fill: none;
stroke-width: 1px;
}
.rangeDiv {
color: #949494;
}
</style>
</head>
<body>
<div class="container-fluid">
<!-- The chart -->
<div class="row">
<div class="col-sm-12">
<div id="chart"></div>
</div>
</div>
<!-- The buttons -->
<div class="row">
<div class="col-sm-6 col-sm-offset-3" style="margin-top: 20px;">
<div id="button" class="btn-group" data-toggle="buttons">
<label id="addButton" class="btn btn-default"><input type="radio" class="btn-options"> Add spiro </label>
<label id="addDashedButton" class="btn btn-default"><input type="radio" class="btn-options"> Add dashed spiro </label>
<label id="resetButton" class="btn btn-default"><input type="radio" class="btn-options"> Reset </label>
</div>
</div>
</div>
<!-- The slider -->
<div class="row">
<div class="col-sm-6 col-sm-offset-3 rangeDiv" style="margin-top: 20px; margin-bottom: 20px;">
Adjust the duration of the next Spirograph you draw (left: faster | right: slower)
<input type="range" id="rangeSlider" min="1" max="120" step="1" value="20" onchange="updateSlider(this.value)">
</div>
</div>
</div>
<script>
////////////////////////////////////////////////////////////
//////////////////////// Set-up ////////////////////////////
////////////////////////////////////////////////////////////
var screenWidth = $(window).innerWidth(),
screenHeight = ( $(window).innerHeight() > 160 ? $(window).innerHeight() - 120 : screenWidth );
mobileScreen = (screenWidth > 500 ? false : true);
var margin = {left: 10, top: 10, right: 10, bottom: 10},
width = screenWidth - margin.left - margin.right - 30,
height = (mobileScreen ? 300 : screenHeight) - margin.top - margin.bottom - 30;
var maxSize = Math.min(width, height) / 2,
drawDuration = 20;
//d3.select("#rangeSlider").attr("value", drawDuration);
var svg = d3.select("#chart").append("svg")
.attr("width", (width + margin.left + margin.right))
.attr("height", (height + margin.top + margin.bottom))
.append("g").attr("class", "wrapper")
.attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")");
var line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
////////////////////////////////////////////////////////////
//////////////////// Draw a Spirograph /////////////////////
////////////////////////////////////////////////////////////
var colors = ["#00AC93", "#EC0080", "#FFE763"];
var numColors = 3;
var startColor = getRandomNumber(0,numColors); //Loop through the colors, but the starting color is random
function addSpiro(doDash) {
var path = svg.append("path")
.attr("class", "spirograph")
.attr("d", line(plotSpiroGraph()) )
.style("stroke", colors[startColor]);
//.style("stroke", "hsla(" + startColor/numColors * 360 + ", 100%, 50%, " + 0.9 + ")");
var totalLength = path.node().getTotalLength();
if (doDash) {
//Adjusted from http://stackoverflow.com/questions/24021971/animate-the-drawing-of-a-dashed-svg-line
//The first number specifies the length of the visible part, the dash, the second number specifies the length of the white part
var dashing = getRandomNumber(1,10) + ", " + getRandomNumber(1,10); //Something such as "6,6" could happen
console.log("Dash pattern is: " + dashing);
//This returns the length of adding all of the numbers in dashing (the length of one pattern in essense)
//So for "6,6", for example, that would return 6+6 = 12
var dashLength =
dashing
.split(/[\s,]/)
.map(function (a) { return parseFloat(a) || 0 })
.reduce(function (a, b) { return a + b });
//How many of these dash patterns will fit inside the entire path?
var dashCount = Math.ceil( totalLength / dashLength );
//Create an array that holds the pattern as often so it will fill the entire path
var newDashes = new Array(dashCount).join( dashing + " " );
//Then add one more dash pattern, namely with a visible part of length 0 (so nothing) and a white part
//that is the same length as the entire path
var dashArray = newDashes + " 0, " + totalLength;
} else {
//For a solid looking line, create a dash pattern with a visible part and a white part
//that are the same length as the entire path
var dashArray = totalLength + " " + totalLength;
}
//Animate the path by offsetting the path so all you see is the white last bit of dashArray
//(which has a length that is the same length as the entire path), and then slowly move this
//out of the way so the rest of the path becomes visible (the stuff at the start of dashArray)
path
.attr("stroke-dasharray", dashArray)
.attr("stroke-dashoffset", totalLength)
.transition().duration(drawDuration * 1000).ease("linear")
.attr("stroke-dashoffset", 0);
}//function addSpiro
////////////////////////////////////////////////////////////
////////////////// Button Activity /////////////////////////
////////////////////////////////////////////////////////////
d3.select("#addButton").on("click", function () {
//Create and draw a spiro
addSpiro(false);
startColor = (startColor+1)%numColors;
//Make the button inactive again
setTimeout( function() { d3.select("#addButton").classed("active", false); }, 200);
});
d3.select("#addDashedButton").on("click", function () {
//Create and draw a dashed spiro
addSpiro(true);
startColor = (startColor+1)%numColors;
//Make the button inactive again
setTimeout( function() { d3.select("#addDashedButton").classed("active", false); }, 200);
});
d3.select("#resetButton").on("click", function () {
//Remove all spiros
d3.selectAll(".spirograph").remove();
getRandomNumber(0,numColors);
//Make the button inactive again
setTimeout( function() { d3.select("#resetButton").classed("active", false); }, 200);
});
function updateSlider(value) {
drawDuration = value;
}
//Start drawing one spirograph after 1 second after reload
setTimeout(function() {
addSpiro(false);
startColor = (startColor+1)%numColors;
}, 1000);
////////////////////////////////////////////////////////////
////////////////// Spirograph functions ////////////////////
////////////////////////////////////////////////////////////
function plotSpiroGraph() {
//Function adjusted from: https://github.com/alpha2k/HTML5Demos/blob/master/Canvas/spiroGraph.html
var R = getRandomNumber(60, maxSize);
var r = getRandomNumber(40, (R * 0.75));
var alpha = getRandomNumber(25, r);
var l = alpha / r;
var k = r / R;
//Create the x and y coordinates for the spirograph and put these in a variable
var lineData = [];
for(var theta=1; theta<=20000; theta += 1){
var t = ((Math.PI / 180) * theta);
var ang = ((l-k)/k) * t;
var x = R * ((1-k) * Math.cos(t) + ((l*k) * Math.cos(ang)));
var y = R * ((1-k) * Math.sin(t) - ((l*k) * Math.sin(ang)));
lineData.push({x: x, y: y});
}
//Output the variables of this spiro
console.log("R: " + R + ", r: " + r + ", alpha: " + alpha + ", l: " + l + ", k: " + k);
return lineData;
}
function getRandomNumber(start, end) {
return (Math.floor((Math.random() * (end-start))) + start);
}
//iFrame handler
var pymChild = new pym.Child();
pymChild.sendHeight();
//setTimeout(function() { pymChild.sendHeight(); }, 2000);
</script>
</body>
</html>