Skip to content

Commit e3f5848

Browse files
author
Peter Linss
committed
[css-backgrounds] added bezier function to spread radius demo
--HG-- extra : rebase_source : b7c08e62788a93710b0239b8b39b88880b529ac8
1 parent fa6d661 commit e3f5848

File tree

1 file changed

+200
-10
lines changed

1 file changed

+200
-10
lines changed

css-backgrounds/spread-radius.html

Lines changed: 200 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
font: inherit;
3535
vertical-align: top;
3636
}
37+
canvas {
38+
border: 1px solid #bbb;
39+
}
3740
</style>
3841

3942
</head>
@@ -59,17 +62,34 @@ <h1>box-shadow spread rounding</h1>
5962

6063
<label>
6164
Algorithm:
62-
<select id="algorithm" size="6">
65+
<select id="algorithm" size="7">
6366
<option value="old">Old</option>
67+
<option value="linear">Linear</option>
6468
<option value="arc">Arc</option>
6569
<option value="hyp">Hyperbolic</option>
66-
<option value="cubic" selected>Cubic</option>
67-
<option value="linear">Linear</option>
70+
<option value="cubic">Cubic</option>
71+
<option value="bezier" selected>Bezier</option>
6872
<option value="custom">Custom</option>
6973
</select>
7074
</label>
7175

72-
<label>f(x) =
76+
<canvas id="plot" width="200" height="200"></canvas>
77+
78+
<div id="bezier_points">
79+
<label>x1:
80+
<input id="x1" value=".25" />
81+
</label>
82+
<label>y1:
83+
<input id="y1" value=".25" />
84+
</label>
85+
<label>x2:
86+
<input id="x2" value=".25" />
87+
</label>
88+
<label>y2:
89+
<input id="y2" value="1" />
90+
</label>
91+
</div>
92+
<label>f(x) =
7393
<input id="custom" value="x < 1? 1-(x-1)*(x-1) : 1" />
7494
</label>
7595
</form>
@@ -79,6 +99,100 @@ <h1>box-shadow spread rounding</h1>
7999
</div>
80100

81101
<script>
102+
CubicBezier = function(x1, y1, x2, y2)
103+
{
104+
this.x1 = x1;
105+
this.y1 = y1;
106+
this.x2 = x2;
107+
this.y2 = y2;
108+
};
109+
110+
CubicBezier.prototype = {
111+
_solveQuadraticEquation: function(a, b, c) {
112+
var discriminant = Math.pow(b, 2) - (4 * a * c);
113+
114+
if (discriminant < 0) {
115+
return [];
116+
}
117+
return [
118+
(-b + Math.sqrt(discriminant)) / (2 * a),
119+
(-b - Math.sqrt(discriminant)) / (2 * a)
120+
];
121+
},
122+
123+
_solveCubicEquation: function(a, b, c, d) {
124+
if (! a) {
125+
return this._solveQuadraticEquation(b, c, d);
126+
}
127+
128+
b /= a;
129+
c /= a;
130+
d /= a;
131+
132+
var p = ((3 * c) - Math.pow(b, 2)) / 3;
133+
var q = ((2 * Math.pow(b, 3)) - (9 * b * c) + (27 * d)) / 27;
134+
var discriminant = Math.pow(q / 2, 2) + Math.pow(p / 3, 3);
135+
136+
if (discriminant === 0) {
137+
return [Math.pow(q / 2, 1 / 3) - (b / 3)];
138+
} else if (discriminant > 0) {
139+
return [Math.pow(-(q / 2) + Math.sqrt(discriminant), 1 / 3) - Math.pow((q / 2) + Math.sqrt(discriminant), 1 / 3) - (b / 3)];
140+
} else {
141+
var r = Math.sqrt(Math.pow(-(p/3), 3));
142+
var phi = Math.acos(-(q / (2 * Math.sqrt(Math.pow(-(p / 3), 3)))));
143+
var s = 2 * Math.pow(r, 1/3);
144+
145+
return [
146+
s * Math.cos(phi / 3) - b / 3,
147+
s * Math.cos((phi + 2 * Math.PI) / 3) - b / 3,
148+
s * Math.cos((phi + 4 * Math.PI) / 3) - b / 3
149+
];
150+
}
151+
},
152+
153+
_solveCubicBezier: function(p0, p1, p2, p3, x) {
154+
p0 -= x;
155+
p1 -= x;
156+
p2 -= x;
157+
p3 -= x;
158+
159+
var roots = this._solveCubicEquation(
160+
p3 - (3 * p2) + (3 * p1) - p0,
161+
(3 * p2) - (6 * p1) + (3 * p0),
162+
(3 * p1) - (3 * p0),
163+
p0
164+
);
165+
166+
var result = 0;
167+
for (var index = 0; index < roots.length; index++) {
168+
var root = Math.round(roots[index] * 1000000000000000) / 1000000000000000;
169+
result = ((result <= root) && (root <= 1)) ? root : result;
170+
}
171+
return result;
172+
},
173+
174+
_bezier: function(t, p0, p1, p2, p3) {
175+
return (Math.pow(1 - t, 3) * p0) + (3 * Math.pow(1 - t, 2) * t * p1) + (3 * (1 - t) * Math.pow(t, 2) * p2) + (Math.pow(t, 3) * p3);
176+
},
177+
178+
x: function(t) {
179+
return this._bezier(t, 0, this.x1, this.x2, 1);
180+
},
181+
182+
y: function(t) {
183+
return this._bezier(t, 0, this.y1, this.y2, 1);
184+
},
185+
186+
tx: function(x) {
187+
return this._solveCubicBezier(0, this.x1, this.x2, 1, x);
188+
},
189+
190+
ty: function(y) {
191+
return this._solveCubicBezier(0, this.y1, this.y2, 1, y);
192+
}
193+
};
194+
195+
82196
function $$(expr, con) {
83197
return Array.prototype.slice.call((con || document).querySelectorAll(expr));
84198
}
@@ -123,6 +237,8 @@ <h1>box-shadow spread rounding</h1>
123237
}
124238
};
125239

240+
Box.bezier = new CubicBezier(x1.value, y1.value, x2.value, y2.value);
241+
126242
Box.constant = 4;
127243

128244
Box.ratios = {
@@ -131,21 +247,25 @@ <h1>box-shadow spread rounding</h1>
131247
},
132248

133249
arc: function(x) {
134-
return x < 1? Math.sqrt(1 - (x-1)*(x-1)) : 1;
250+
return Math.sqrt(1 - (x-1)*(x-1));
135251
},
136252

137253
hyp: function(x) {
138254
return 1-1/(Box.constant*x+1);
139255
},
140256

141257
cubic: function(x) {
142-
return x < 1? 1 + Math.pow(x-1, 3) : 1;
258+
return 1 + Math.pow(x-1, 3);
143259
},
144260

145261
linear: function(x) {
146-
return x < 1? x : 1;
262+
return x;
147263
},
148264

265+
bezier: function(x) {
266+
return Box.bezier.y(Box.bezier.tx(x));
267+
},
268+
149269
custom: function (x) {
150270
try {
151271
return eval(custom.value);
@@ -157,7 +277,7 @@ <h1>box-shadow spread rounding</h1>
157277
};
158278

159279
Box.spreadRounding = function(r, spread) {
160-
var ratio = Box.ratio(r/spread);
280+
var ratio = (r/spread) < 1 ? Box.ratio(r/spread) : 1;
161281

162282
return r + spread * ratio;
163283
};
@@ -178,6 +298,8 @@ <h1>box-shadow spread rounding</h1>
178298
$$('.box').forEach(function (box) {
179299
box.box.spread = +spread;
180300
});
301+
302+
redrawPlot();
181303
};
182304

183305
bradius.oninput = bradius.onchange = function() {
@@ -186,19 +308,86 @@ <h1>box-shadow spread rounding</h1>
186308
$$('.box').forEach(function (box) {
187309
box.box.borderRadius = +radius;
188310
});
311+
312+
redrawPlot();
189313
};
190314

191315
algorithm.onchange = function () {
192316
Box.ratio = Box.ratios[this.value];
193317

194-
custom.parentNode.style.visibility = this.value == 'custom'? '' : 'hidden';
318+
bezier_points.style.display = this.value == 'bezier' ? '' : 'none';
319+
custom.parentNode.style.display = this.value == 'custom'? '' : 'none';
195320

196321
Box.redrawAll();
322+
redrawPlot();
197323
};
198324

325+
var plotContext = plot.getContext('2d');
326+
plotContext.lineWidth = 1 / plot.height;
327+
plotContext.translate(0, plot.height);
328+
plotContext.scale(plot.width, -plot.height);
329+
199330
algorithm.onchange();
200331

201-
custom.oninput = Box.redrawAll;
332+
function redrawPlot() {
333+
var context = plot.getContext('2d');
334+
335+
// draw function
336+
context.strokeStyle = "black";
337+
context.clearRect(0, 0, 1, 1);
338+
context.beginPath();
339+
context.moveTo(0, Box.ratio(0));
340+
for (var x = 0; x <= 1; x += .005) {
341+
context.lineTo(x, Box.ratio(x));
342+
}
343+
context.stroke();
344+
345+
// draw ratio
346+
var ratio = Math.min(bradius.value / spread.value, 1);
347+
context.strokeStyle = "#ccc";
348+
context.beginPath();
349+
context.moveTo(ratio, 0);
350+
context.lineTo(ratio, 1);
351+
context.stroke();
352+
context.beginPath();
353+
context.moveTo(0, ratio < 1 ? Box.ratio(ratio) : 1);
354+
context.lineTo(1, ratio < 1 ? Box.ratio(ratio) : 1);
355+
context.stroke();
356+
357+
if ('bezier' == algorithm.value) {
358+
context.strokeStyle = "red";
359+
context.beginPath();
360+
context.moveTo(0, 0);
361+
context.lineTo(x1.value, y1.value);
362+
context.stroke();
363+
context.beginPath();
364+
context.moveTo(x1.value, y1.value + .025);
365+
context.arc(x1.value, y1.value, .025, 0, 360, false);
366+
context.stroke();
367+
context.strokeStyle = "green";
368+
context.beginPath();
369+
context.moveTo(1, 1);
370+
context.lineTo(x2.value, y2.value);
371+
context.stroke();
372+
context.beginPath();
373+
context.moveTo(x2.value, y2.value + .025);
374+
context.arc(x2.value, y2.value, .025, 0, 360, false);
375+
context.stroke();
376+
}
377+
}
378+
379+
custom.oninput = function() {
380+
Box.redrawAll();
381+
redrawPlot();
382+
};
383+
384+
x1.oninput = y1.oninput = x2.oninput = y2.oninput = function() {
385+
if (this.value < 0) this.value = 0;
386+
if (this.value > 1) this.value = 1;
387+
Box.bezier = new CubicBezier(x1.value, y1.value, x2.value, y2.value);
388+
Box.redrawAll();
389+
redrawPlot();
390+
};
202391

203392
//constant.oninput = function() {
204393
// Box.constant = +this.value;
@@ -214,6 +403,7 @@ <h1>box-shadow spread rounding</h1>
214403
});
215404

216405
Box.redrawAll();
406+
redrawPlot();
217407
</script>
218408

219409
</body>

0 commit comments

Comments
 (0)