Skip to content

Instantly share code, notes, and snippets.

@cythux
Created November 2, 2014 20:46
Show Gist options
  • Save cythux/b51d6521b8cdf13ee58d to your computer and use it in GitHub Desktop.
Save cythux/b51d6521b8cdf13ee58d to your computer and use it in GitHub Desktop.
A Pen by Hugo Giraudel.
<div class="grid grid-1"><span><span></span></span></div>
<div class="grid grid-2"><span><span></span></span></div>
<div class="grid grid-3"><span><span></span></span></div>
/**
* Little helper to create a circle
* @group control-points
* @access private
* @param {Number} $size - Circle size
* @output Dimensions, margin and border-radius
*/
@mixin circle($size) {
width: $size;
height: $size;
margin: -($size/2);
border-radius: 50%;
}
/**
* Helper to position an item in absolute context
* @param {Number} $top (null) - Top offset
* @param {Number} $right (null) - Right offset
* @param {Number} $bottom (null) - Bottom offset
* @param {Number} $left (null) - Left offset
* @output `position: absolute` and offsets
*/
@mixin absolute($top: null, $right: null, $bottom: null, $left: null) {
position: absolute;
top: $top;
right: $right;
bottom: $bottom;
left: $left;
}
/**
* Linear interpolation
* @author Tim Severien
* @param {Number} $a
* @param {Number} $b
* @param {Number} $p
* @return {Number}
*/
@function lerp($a, $b, $p) {
@return ($b - $a) * $p + $a;
}
/**
* Linear interpolation points
* @author Tim Severien
* @param {Number} $a
* @param {Number} $b
* @param {Number} $p
* @return {List}
*/
@function lerp-point($a, $b, $p) {
@return lerp(nth($a, 1), nth($b, 1), $p), lerp(nth($a, 2), nth($b, 2), $p);
}
/**
* Bezier Reduce
* @author Tim Severien
* @param {List} $points
* @param {Number} $p
* @return {Number}
*/
@function bezier-reduce($points, $p) {
@while length($points) > 1 {
$tmp: ();
@for $i from 1 to length($points) {
$tmp: append($tmp, lerp-point(nth($points, $i), nth($points, $i + 1), $p));
}
$points: $tmp;
}
@return nth($points, 1);
}
/**
* Bezier shadow
* @param {List} $points - List of points from Bezier
* @param {Number} $detail - Number of particles
* @output box-shadow
* @author Tim Severien
*/
@mixin bezier-shadow($points, $detail) {
$shadow: ();
@for $i from 0 to $detail {
$point: bezier-reduce($points, $i / $detail);
$shadow: append($shadow, nth($point, 1) nth($point, 2), comma);
}
box-shadow: $shadow;
}
/**
* Curve wrapper
* @access private
* @param {Map} $conf - Curve configuration
* @requires {mixin} absolute
* @output Contexte
*/
@mixin draw-curve-wrapper($conf) {
@include absolute($top: 0, $right: 0, $bottom: 0, $left: 0);
color: map-get($conf, 'color');
}
/**
* Display dots with `::after` pseudo-element
* @access private
* @param {Map} $conf - Curve configuration
* @requires {mixin} absolute
* @requires {mixin} circle
* @output Dots
*/
@mixin draw-dots($conf) {
$args: map-get($conf, 'points');
$size: map-get($conf, 'size');
&::after {
content: '';
@include circle(4px);
@include absolute($left: 0, $top: 0);
@include bezier-shadow((
0 $size,
(nth($args, 1) * $size) ((1 - nth($args, 2)) * $size),
(nth($args, 3) * $size) ((1 - nth($args, 4)) * $size),
$size 0
), map-get($conf, 'detail'));
}
}
/**
* Draw control-points as well as lines getting to those
* @access private
* @param {Map} $conf - Curve configuration
* @requires {mixin} absolute
* @requires {mixin} circle
* @output control-points
*/
@mixin draw-control-points($conf) {
$args: map-get($conf, 'points');
$size: map-get($conf, 'size');
$color: map-get($conf, 'color');
$x1: nth($args, 1);
$y1: nth($args, 2);
$x2: nth($args, 3);
$y2: nth($args, 4);
&::before {
content: '';
@include absolute;
@include circle(10px);
box-shadow:
0 $size 0 0 tomato,
$size 0 0 0 deepskyblue,
($size * $x1) $size - ($size * $y1) 0 0 tomato,
($size * $x2) $size - ($size * $y2) 0 0 deepskyblue;
}
> * {
@include absolute($top: 0, $right: 0, $bottom: 0, $left: 0);
&::before {
@include absolute($left: 0, $bottom: 0);
content: '';
width: $x1 * 100%;
height: $y1 * 100%;
background: linear-gradient(
if($x1 == 1, 90deg, 0 - atan($y1 / $x1) * 1rad),
transparent calc(50% - 1px),
$color calc(50% - 1px),
$color calc(50% + 1px),
transparent calc(50% + 1px)
);
}
&::after {
$v: abs($x2 * 100 - 100);
$w: abs($y2 * 100 - 100);
@include absolute($top: 0, $right: 0);
width: if($v == 0, 1px, $v * 1%);
height: if($w == 0, 1px, $w * 1%);
content: '';
background: linear-gradient(
if($x2 == 1, 90deg, 0 - atan(($y2 - 1) / ($x2 - 1)) * 1rad),
transparent calc(50% - 1px),
$color calc(50% - 1px),
$color calc(50% + 1px),
transparent calc(50% + 1px)
);
}
}
}
/**
* Main function, drawing a Bezier function
* @access private
* @param {Map} $conf - Curve configuration
* @output Dots and possibly control-points
*/
@mixin draw-curve($conf) {
// Print the wrapper
@include draw-curve-wrapper($conf);
// Print the dots
@include draw-dots($conf);
// Print the control-points
@if map-get($conf, 'control-points') != false {
@include draw-control-points($conf);
}
}
/**
* Draw coords system
* @access private
* @param {Map} $conf - Curve configuration
* @param {Bool} $display-name (false) - Enable/disable name display
*/
@mixin draw-system($conf) {
width: map-get($conf, 'size');
height: map-get($conf, 'size');
position: relative;
color: map-get($conf, 'color');
border-left: 2px solid;
border-bottom: 2px solid;
border-top: 1px dashed;
border-right: 1px dashed;
&::after,
&::before {
position: absolute;
bottom: -1.75em;
text-transform: uppercase;
font-size: .75em;
}
@if map-get($conf, 'informations') {
@if map-has-key($conf, 'name') {
// Display name
&::before {
content: "#{map-get($conf, 'name')}";
left: 0;
}
}
// Display values
&::after {
content: "#{map-get($conf, 'points')}";
right: 0;
}
}
// Print the curve
> * {
@include draw-curve($conf);
}
}
/**
* Draw a cubic bezier function.
* Also initialize a global variable holding the configuration.
* @access public
* @param {Number} $x1 - X of first pair
* @param {Number} $y1 - Y of first pair
* @param {Number} $x2 - X of second paid
* @param {Number} $y2 - Y of second pair
* @param {Map} $options - Map of options
*/
@mixin cubic-bezier($x1, $y1, $x2, $y2, $options: ()) {
// Default options
$options: map-merge((
// Enable/disable control-points
'control-points': true,
// Extra informations
'informations': true,
// Size of the grid
'size': 300px,
// Color scheme
'color': #999,
// Points from the curve
'points': ($x1, $y1, $x2, $y2),
// Number of dots on the curve
'detail': 30
), $options);
// Start printing things
@include draw-system($options);
}
/**
* DEMO *
**/
.grid {
margin: 1em;
float: left;
}
.grid-1 {
@include cubic-bezier(.42, 0, 1, 1, (
'name': 'ease-in'
));
}
.grid-2 {
@include cubic-bezier(.42, 0, .58, 1, (
'name': 'ease-in-out'
));
}
.grid-3 {
@include cubic-bezier(.13, .88, .5, .42);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment