-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Expand file tree
/
Copy path_math.scss
More file actions
199 lines (179 loc) · 5.96 KB
/
Copy path_math.scss
File metadata and controls
199 lines (179 loc) · 5.96 KB
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
// Foundation for Sites
// https://get.foundation
// Licensed under MIT Open Source
@use "sass:math";
////
/// @group functions
////
/// Finds the greatest common divisor of two integers.
///
/// @param {Number} $a - First number to compare.
/// @param {Number} $b - Second number to compare.
///
/// @returns {Number} The greatest common divisor.
@function gcd($a, $b) {
// From: http://rosettacode.org/wiki/Greatest_common_divisor#JavaScript
@if ($b != 0) {
@return gcd($b, $a % $b);
}
@else {
@return math.abs($a);
}
}
/// Handles decimal exponents by trying to convert them into a fraction and then use a nth-root-algorithm for parts of the calculation
///
/// @param {Number} $base - The base number.
/// @param {Number} $exponent - The exponent.
///
/// @returns {Number} The product of the exponentiation.
@function pow($base, $exponent, $prec: 16) {
@if (floor($exponent) != $exponent) {
$prec2: pow(10, $prec);
$exponent: round($exponent * $prec2);
$denominator: gcd($exponent, $prec2);
@return nth-root(pow($base, divide($exponent, $denominator)), divide($prec2, $denominator), $prec);
}
$value: $base;
@if $exponent > 1 {
@for $i from 2 through $exponent {
$value: $value * $base;
}
}
@else if $exponent < 1 {
@for $i from 0 through -$exponent {
$value: divide($value, $base);
}
}
@return $value;
}
@function nth-root($num, $n: 2, $prec: 12) {
// From: http://rosettacode.org/wiki/Nth_root#JavaScript
$x: 1;
@for $i from 0 through $prec {
$x: divide(1, $n) * (($n - 1) * $x + divide($num, pow($x, $n - 1)));
}
@return $x;
}
/// Calculates the height as a percentage of the width for a given ratio.
/// @param {List} $ratio - Ratio to use to calculate the height, formatted as `x by y`.
/// @return {Number} A percentage value for the height relative to the width of a responsive container.
@function ratio-to-percentage($ratio) {
$w: nth($ratio, 1);
$h: nth($ratio, 3);
@return divide($h, $w) * 100%;
}
/// Parse the given `$fraction` to numerators and denumerators.
///
/// @param {*} $fraction - Value representing a fraction to parse. It can be formatted as `50%`, `1 of 2`, `1/2` or `50` (no denominator would be returned).
///
/// @return {List} List of parsed values with numerator at first position and denumerator as second. These values may be null.
@function zf-parse-fraction($fraction) {
@if type-of($fraction) == 'number' {
// "50%"
@if unit($fraction) == '%' {
@return (strip-unit($fraction), 100);
}
@else if (unit($fraction) == '') {
// "0.5"
@if $fraction < 1 {
@return ($fraction * 100, 100);
}
// "50"
@else {
@return ($fraction, null);
}
}
}
@else if type-of($fraction) == 'list' {
// "50 of 100", "50/100"...
@if length($fraction) == 3
and type-of(nth($fraction, 1) == 'number')
and type-of(nth($fraction, 3) == 'number') {
@return (nth($fraction, 1), nth($fraction, 3));
}
}
@return (null, null);
}
/// Returns whether the given `$value` represents a fraction. Supports formats like `50%`, `1 of 2`, `1 per 2` or `1/2`.
///
/// @param {*} $value - Value to test.
/// @param {Boolean} $allow-no-denominator [false] - If `true`, simple numbers without denominators like `50` are supported.
///
/// @return {Boolean} `true` if `$value` represents a fraction, `false` otherwise.
@function zf-is-fraction($value, $allow-no-denominator: false) {
$parsed: zf-parse-fraction($value);
@return not(nth($parsed, 1) == null
or (nth($parsed, 2) == null and $allow-no-denominator == false));
}
/// Calculate a percentage from a given fraction.
///
/// @param {Number|List} $fraction - Value representing a fraction to use to calculate the percentage, formatted as `50` (relative to `$denominator`), `50%`, `1 of 2` or `1/2`.
/// @param {Number|List} $denominator - Default value to use as denominator when `$fraction` represents an absolute value.
@function fraction-to-percentage(
$fraction,
$denominator: null
) {
$parsed: zf-parse-fraction($fraction);
$parsed-nominator: nth($parsed, 1);
$parsed-denominator: nth($parsed, 2);
@if $parsed-nominator == null {
@error 'Wrong syntax for "fraction-to-percentage()". Use a number, decimal, percentage, or "n of n" / "n/n".';
}
@if $parsed-denominator == null {
@if type-of($denominator) == 'number' {
$parsed-denominator: $denominator;
}
@else {
@error 'Error with "fraction-to-percentage()". A default "$denominator" is required to support absolute values';
}
}
@return math.percentage(divide($parsed-nominator, $parsed-denominator));
}
/// Divide the given `$divident` by the given `$divisor`.
///
/// @param {Number} $divident - The divident.
/// @param {Number} $divisor - The divisor.
/// @param {Number} $precision - The precision decimals for the division.
///
/// @return {Number} The product of the division.
@function divide($dividend, $divisor, $precision: 12) {
$sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
$dividend: math.abs($dividend);
$divisor: math.abs($divisor);
@if $dividend == 0 {
@return 0;
}
@if $divisor == 0 {
@error 'Cannot divide by 0';
}
$remainder: $dividend;
$result: 0;
$factor: 10;
@while ($remainder > 0 and $precision >= 0) {
$quotient: 0;
@while ($remainder >= $divisor) {
$remainder: $remainder - $divisor;
$quotient: $quotient + 1;
}
$result: $result * 10 + $quotient;
$factor: $factor * 0.1;
$remainder: $remainder * 10;
$precision: $precision - 1;
@if ($precision < 0 and $remainder >= $divisor * 5) {
$result: $result + 1;
}
}
$result: $result * $factor * $sign;
$dividend-unit: unit($dividend);
$divisor-unit: unit($divisor);
$unit-map: (
'px': 1px,
'rem': 1rem,
'em': 1em,
'%': 1%
);
@if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
$result: $result * map-get($unit-map, $dividend-unit);
}
@return $result;
}