I have many spans that are one next to each other and I'd like to add some linear-gradient effect - so the first one has background-color: $a, the last one background-color: $b and the spans between the "transition color from $a to $b". If I'm not making any sense, this image will help you:
I tried with lighten(), but it only uses one color.
Here's the current SCSS:
$starting_color: #177DEF;
$ending_color: #2FF0D5;
$elements: 51;
#for $i from 0 to $elements {
span:nth-child(#{$i}) {
height: random(260) + px;
background-color: lighten($starting_color, $i);
}
}
Whole fiddle on Codepen
How can I create this "effect"? Possible with some step parameter (step count = all spans)
This is quite lengthy, but it works:
//$blue: #177DEF;
$firstR: 23;
$firstG: 239;
$firstB: 125;
$blue: rgb(23, 125, 239);
//$green: #2FF0D5;
$secondR: 47;
$secondG: 240;
$secondB: 213;
$green: rgb(47, 240, 213);
body{
background-color: #000;
}
#panel {
font-size: 0;
}
span {
font-size: 16px;
display: inline-block;
vertical-align: bottom;
width: 10px;
&:not(:first-of-type) {
margin-left: 2px;
}
}
$elements: 51;
$redDiv: ($firstR - $secondR) / $elements;
#if $redDiv < 0 {
$redDiv: $redDiv * -1
}
$greenDiv: ($firstG - $secondG) / $elements;
#if $greenDiv < 0 {
$greenDiv: $greenDiv * -1
}
$blueDiv: ($firstB - $secondB) / $elements;
#if $blueDiv < 0 {
$blueDiv: $blueDiv * -1
}
#for $i from 0 to $elements {
$redValue: $redDiv * $i;
$greenValue: $greenDiv * $i;
$blueValue: $blueDiv * $i;
span:nth-child(#{$i}) {
height: random(260) + px;
background-color: rgb($firstR + $redValue, $firstG + $greenValue, $firstB + $blueValue);
}
}
I converted the hexadecimal values to RGB here, then made separate variables for each red, green, blue value in both colors.
Subtract the second value from the first then divide by how many elements (this gives you the amount of change needed each iteration).
Make sure the values aren't negative with #if.
Calculate the change by multiplying by $i and then add/subtract that change depending upon which value was lesser (first or second). If first value is less then $first + $value, if second value is less then $first - $value.
This was the only part that needs to be changed depending on the colors, the rest will work for any RGB value.
Codepen: http://codepen.io/anon/pen/ezpmXJ
Related
Let's say I have a simple flex container with 2 flex items where the flex items' sizes exceed the containers size - where flex-shrink will be used..like so:
.container {
width: 600px;
outline: 5px solid;
display: flex;
}
section {
flex: 0 1 600px;
background: salmon;
}
aside {
flex: 0 1 200px;
background: aqua;
}
<div class="container">
<section>
<h2>Main content here</h2>
</section>
<aside>
<h2>Some side content</h2>
</aside>
</div>
Codepen demo
In the above example: The container is 600px, the section flex-item has flex basis of 600px and the aside has flex-basis of 200px - so the negative space is 200px.
So being that both flex items have the same flex-shrink factor of 1 - I expected that both flex items would shrink by 100px with the section getting a width of 600px - 100px = 500px and the aside getting 200px - 100px = 100px
But the result was actually that the section shrinks by 150px to 450px and the aside shrinks by 50px to 150px
So then I looked at the spec and I found this:
Note: The flex shrink factor is multiplied by the flex base size when
distributing negative space. This distributes negative space in
proportion to how much the item is able to shrink, so that e.g. a
small item won’t shrink to zero before a larger item has been
noticeably reduced.
So now I understand that when calculating flex-shrink on a flex item not only is the flex shrink factor taken into account, but also the flex base size (here, defined by the flex-basis property)
The problem is that I can't seem to do the math to calculate flex-shrink.
So just to continue with the above example: say I change the shrink factor of the section to 2...
.container {
width: 600px;
outline: 5px solid;
display: flex;
}
section {
flex: 0 2 600px;
background: salmon;
}
aside {
flex: 0 1 200px;
background: aqua;
}
<div class="container">
<section>
<h2>Main content here</h2>
</section>
<aside>
<h2>Some side content</h2>
</aside>
</div>
Codepen demo #2
... the result is that section gets a width of 428px and aside gets a width of 121px
Can someone explain how to calculate this?
Neglecting lots of details, the algorithm is something like this
let sumScaledShrinkFactors = 0,
remainingFreeSpace = flexContainer.innerMainSize;
for (let item of flexItems) {
remainingFreeSpace -= item.outerFlexBasis;
item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor;
sumScaledShrinkFactors += item.scaledShrinkFactor;
}
for (let item of flexItems) {
let ratio = item.scaledShrinkFactor / sumScaledShrinkFactors;
item.innerWidth = item.innerFlexBasis + ratio * remainingFreeSpace;
}
So the formula is like
flexBasis * (1 + shrinkFactor / sumScaledShrinkFactors * remainingFreeSpace)
First case
1*600px + 1*200px ─┐ width
│ ───────
600px * (1 + 1 / 800px * -200px) = 450px
200px * (1 + 1 / 800px * -200px) = 150px
│ ───────
600px - (600px + 200px) ────┘ 600px
Second case
2*600px + 1*200px ──┐ width
│ ───────
600px * (1 + 2 / 1400px * -200px) ≈ 429px
200px * (1 + 1 / 1400px * -200px) ≈ 171px
│ ───────
600px - (600px + 200px) ─────┘ 600px
I want to create a fixed non-flexible very damn static grid of 1200px.
So I figured out, I need 90px for column-width, 12 columnts, 10px of gutter and 1200px of max-width.
Well.. the following are my settings and it gives me an error "invalid null opearation: 11 times null "
$susy: (
flow: ltr,
math: static,
output: float,
gutter-position: after,
container: auto,
container-position: center,
columns: 12,
gutters: 10px,
column-width: 90px,
global-box-sizing: content-box,
last-flow: to,
debug: (
image: show,
color: rgba(#66f, .25),
output: overlay,
toggle: top right,
),
use-custom: (
background-image: true,
background-options: false,
box-sizing: true,
clearfix: false,
rem: true,
)
);
style.scss>
#import "grids";
body{
#include container($susy);
max-width: 1200px;
border: solid thin red;
height:10px;
}
You need to specify gutters proportionally to your columns.
In this case:
gutters: 1/9,
The end result (being your columns 90px) would be gutters 10px wide. You can specify your gutters width in pixels by expressing it as a proportion.
As per the docs, you can speficy gutter width in pixels, by putting the column width as well. E.g.:
gutters: 10px/90px
Alhtough the result is exactly the same. And if you put in a value that doesn't match with your column width, you won't get the pixel width you say, but the appropriate fraction.
So having:
column-width: 100px,
gutters: 10px/50px,
will leave you with 20px wide gutters. Because of math. :)
Pen showing it working here.
And finally, your layout is 1190px wide and not 1200px because:
12 columns * 90px = 1080px
11 gutters * 10px = 110px.
1180px + 110px = 1190px.
I'm having trouble positioning last-child of inline-block horizontal scrolling site. In firefox everything looks ok, but in Chrome last child of articles is somehow pushed down, for about 18px. Of course, I've tried to separately assign the "vertical-align:top" to last element, but still no {good} result ...
Here's my site: http://rup.fiser.biz/braunova/category/scenography/
.post {
height: 351px;
float: left;
display: inline-block;
}
remove float: left; as you have display: inline-block (float or display, can't have both as far as I know)
.site-content article {
margin: 0 20px 0 0;
padding: 0;
}
and remove margin if you want to move the las element next to others
I have a set of 2d points distributed randomly. I need to perform a time intensive operation on a small subset of these points but I need to first figure out what points I need to perform this time intensive operation on. To determine what points I need they must pass a series of geometric criteria.
The most basic criteria is are they within a certain distance of a specific point. The second most basic criteria is whether they are contained within a circle sector (a 2-D cone) extending out from that specific point. (Edit: This operation is called regularly with a different specific point each time but the same set of 2d points.)
My initial thought was to create a grid containing the 2d points, then iterate along the cone grabbing grid squares that it intersects. Depending on the size of the grid it would filter out the vast majority of unneeded 2d points. Unfortunately the embedded system I'm running on is severely memory constrained so a large (by our standards not anyone elses) 2d array would be too memory intensive.
I have been trying to investigate using KD trees to speed up the calculation but I haven't been able to find an algorithm relating circle sectors and kd-trees.
Is there an efficient algorithm for finding what 2d points lie within a circle sector?
Just a note our particular system is slow at both floating point math and trigonometry so a solution that involves less of those is superior one that requires a lot of it.
It's possible to check if a point is inside a sector with only integer arithmetic and the basic operations of addition, subtraction and multiplication.
For a point to be inside a circular sector, it has to meet the following tests:
It has to be positioned counter-clockwise from the start "arm" of the sector.
It has to be positioned clockwise from the end arm of the sector.
It has to be closer to the center of the circle than the sector's radius.
Clockwise tests
To test if a vector v2 is clockwise to a another vector v1, do the following:
Find the counter-clockwise normal vector of v1. The normal vector is at a 90 degrees angle to the original vector. This is straightforward to do: if v1=(x1,y1), then the counter-clockwise normal is n1=(-y1,x1).
Find the size of the projection of v2 on the normal. This can be done by calculating the dot product of v2 and the normal.
projection = v2.x*n1.x + v2.y*n1.y
If the projection is a positive number, then the v2 is positioned counter-clockwise to v1. Otherwise, v2 is clockwise to v1.
Here's a counter-clockwise example:
And a clockwise example:
The steps can be combined:
function areClockwise(v1, v2) {
return -v1.x*v2.y + v1.y*v2.x > 0;
}
Radius test
The radius test is straightforward. Just check if the distance of the point from the center of the circle is less than the desired radius. To avoid computing square roots, we can compare the square of the distance with the square of the radius instead.
function isWithinRadius(v, radiusSquared) {
return v.x*v.x + v.y*v.y <= radiusSquared;
}
Putting it together
The complete sector test looks something like:
function isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared) {
var relPoint = {
x: point.x - center.x,
y: point.y - center.y
};
return !areClockwise(sectorStart, relPoint) &&
areClockwise(sectorEnd, relPoint) &&
isWithinRadius(relPoint, radiusSquared);
}
The following sample page demonstrates this over several thousand points. You can experiment with the code at: http://jsbin.com/oriyes/8/edit.
Sample source code
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<style>
.canvas {
position: absolute;
background: #f4f4f4;
border: 8px solid #f4f4f4;
width: 400px;
height: 400px;
}
.dot {
position: absolute;
font: 16px Arial;
}
.out { color: #ddd; }
.in { color: #00dd44; }
</style>
<script>
function isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared) {
var relPoint = {
x: point.x - center.x,
y: point.y - center.y
};
return !areClockwise(sectorStart, relPoint) &&
areClockwise(sectorEnd, relPoint) &&
isWithinRadius(relPoint, radiusSquared);
}
function areClockwise(v1, v2) {
return -v1.x*v2.y + v1.y*v2.x > 0;
}
function isWithinRadius(v, radiusSquared) {
return v.x*v.x + v.y*v.y <= radiusSquared;
}
$(function() {
var $canvas = $("#canvas");
var canvasSize = 400;
var count = 4000;
// define the sector
var center = { x: canvasSize / 2, y: canvasSize / 2 };
var sectorStart = { x: 4, y: 1 };
var sectorEnd = { x: 1, y: 4 };
var radiusSquared = canvasSize * canvasSize / 4;
// create, draw and test a number of random points
for (var i = 0; i < count; ++i) {
// generate a random point
var point = {
x: Math.random() * canvasSize,
y: Math.random() * canvasSize
};
// test if the point is inside the sector
var isInside = isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared);
// draw the point
var $point = $("<div class='dot'></div>")
.css({
left: point.x - 3,
top: canvasSize - point.y - 8 })
.html("•")
.addClass(isInside ? "in" : "out")
.appendTo($canvas);
}
});
</script>
</head>
<body>
<div id="canvas" class="canvas"></div>
</body>
</html>
Notes, caveats and limitations
You have to specify the boundaries of the sector in terms of vectors. The screenshot above, for example, shows a sector stretching between the vectors of (4,1) and (1,4).
If your sector is specified in other terms, e.g. angles, you will have to convert that to vectors first, e.g. using the tan() function. Fortunately, you only have to do this once.
The logic here works for sectors with an inner angle of less than 180 degrees. If your sectors can span a larger angle, you'll have to modify it.
Additionally, the code assumes that you know which of the bounding vectors of the sector is the "start" and which is the "end". If you don't, you can run the areClockwise() on them to find out.
Note that while all this can be done with integer arithmetic, both the radius and clockwise tests use a larger range of numbers, due to squaring x's and y's and multiplying them together. Make sure to use integers of sufficient bits to hold the results.
I know you don't want trigonometry, but you could convert each point (in your subset) to its polar coordinates (where the origin is your specific point) and threshold r,theta where r < R and T1 < theta < T2 corresponding to the sector. It's certainly memory efficient!
#Oren Trutner answer was great so I decided to make a visual example of it and make some improvements to make it work on all angles.
no further speaking, check the example below.
$(document).on('keypress',function (e) {
if(e.which === 13)
{
$("#calc").click();
}
});
function areClockwise(v1, v2) {
return -v1.x*v2.y + v1.y*v2.x > 0;
}
function vector(x = 0, y = 0) {
return {x:x,y:y}
}
function degToRad(degree) {
return degree * Math.PI / 180;
}
function isIn()
{
let illustration = $("#illustration");
illustration.html("");
let r = 250;
let fieldOfViewAngle = 150;
let x = Number($("#x").val());
let y = Number($("#y").val());
let startAngle = Number($("#startAngle").val());
let startSectorAngle = degToRad(startAngle);
let endSectorAngle = degToRad(startAngle+fieldOfViewAngle);
$("#startLine").attr("x2",250 + r*Math.cos(-startSectorAngle)).attr("y2",250 + r*Math.sin(-startSectorAngle));
$("#endLine").attr("x2",250 + r*Math.cos(-endSectorAngle)).attr("y2",250 + r*Math.sin(-endSectorAngle));
$("#point").attr("cx",250 +x).attr("cy",250 -y);
let sectorStartVector = vector(r * Math.cos(startSectorAngle),r * Math.sin(startSectorAngle));
let sectorEndVector = vector(r * Math.cos(endSectorAngle),r * Math.sin(endSectorAngle));
let relPoint = vector(x,y);
if(!this.areClockwise(sectorStartVector, relPoint) &&
this.areClockwise(sectorEndVector, relPoint))
$("#result").html("Result: in");
else{
$("#result").html("Result: out")
}
}
.flixy {
display: flex;
flex-direction: column;
}
.flixy > div {
margin-bottom: 20px;
width:300px
}
.flixy > div > input {
float: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result"></div>
<div class="flixy">
<div class="input-group">
<label>X</label>
<input id="x">
</div>
<div class="input-group">
<label>Y</label>
<input id="y">
</div>
<div class="input-group">
<label>Start angle</label>
<input id="startAngle">
</div>
<div class="input-group">
<label>Radius</label>
<input value="250" disabled>
</div>
<div class="input-group">
<label>Theta</label>
<input value="150" disabled>
</div>
</div>
<button onclick="isIn()" id="calc">calc</button>
<div style="width: 500px;height: 500px; overflow: visible">
<svg width="500" height="500" style="overflow: visible">
<circle cx="250" cy="250" r="250" stroke="black" stroke-width="3" fill="yellow"></circle>
<line id="startLine" x1="250" y1="250" x2="500" y2="250" style="stroke:#2fa360;stroke-width:2" />
<line id="endLine" x1="250" y1="250" x2="500" y2="250" style="stroke:#1d68a7;stroke-width:2" />
<circle id="point" cx="250" cy="250" r="5" fill="red"></circle>
</svg>
</div>
Lets say I wrote a simple CSS rule like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
And I need 10, so I copied it 9 times.
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
etc.
Now I want to change the star_10 and 0 0 with incremented values so it looks like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_9 {
background: url(stars.png) no-repeat 0 -18px;
}
.star_8 {
background: url(stars.png) no-repeat 0 -36px;
}
.star_7 {
background: url(stars.png) no-repeat 0 -54px;
}
and so on...
So how can I search/replace every instance, do a calculation and write it?
You can do it easily with a macro. Lets say you have only this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
Place your cursor over the first dot (in .star10) and type the following in normal mode:
qa3yy3jp^Xjt;18^Xk0q
Explaining:
qa will start a macro recording in register "a".
3yy will yank (copy) the following 3 lines.
3j will place the cursor 3 lines down.
p will paste the past yanked text.
^X (ctrl+x) will decrement the star class number.
j will place your cursor one line down.
t; will place your cursor before the next ; in the current line.
18^X will decrement the y coordinate of backround by 18;
k will put the cursor one line up,
0 will put the cursor at the beggining of the line.
q will finish the macro recording.
After that, you may have something like this.
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_9 {
background: url(stars.png) no-repeat 0 -18;
}
That's it. Just place your cursor at the dot on .star_9 and press 8#a to execute the macro recorded in register a eight more times.
You can use the s/pattern/replace construct with the \= symbol in order to evaluate a function or expression, as shown:
Decrementing the .star_10:
let g:decr = 11
fu! Decr()
let g:decr = g:decr - 1
return g:decr
endfu
:%s/.star_10/\=".star_" . Decr()/
Similarly, you'd do
let g:decr_18 = 18
fu! Decr18()
let g:decr_18 = g:decr_18 - 18
return g:decr_18
endfu
and then replace the 0 0; with a
:%s/no-repeat 0 0;/\="no-repeat 0 " . Decr18() . "px"/
For both functions, a (global) variable is declared that is manipulated within the functions and returned. The functin itself is called for every line matching the pattern. the pattern is substituted with the expression following the \=.
You could probably write a function for this, but I usually do something simpler. I use a key macro involving the ^A and ^X keys (increment and decrement a number). Use qa to start recording, do your stuff, using those keys with count modifiers (e.g 18^X), and just do say, 10# afterwards.
I needed this solution but also with leading zero support. My use of the original question is more like Example 1 than what Example 2 (this was the original example).
I created a function called SearchIncr() (search, replace, and increment).
There are four required arguments: target_string, replacement_string, start_value, increment_value.
There are also two optional arguments: leading_zeros, position
leading_zeros is a positive integer value, and position is 'before' or 'after'. See example 2.
Example 1
:'<,'>call SearchIncr("0 0","new",1,5,8)
If the file looks like this:
what 0 0 post
areu 0 0 post
doin 0 0 post
You will then get:
what new00000001 post
areu new00000006 post
doin new00000011 post
Example 2
:'<,'>call SearchIncr("0;","px;",-18,-18,0,'after')
If the file looks like this:
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
.star_10 {
background: url(stars.png) no-repeat 0 0;
}
You will then get:
.star_10 {
background: url(stars.png) no-repeat 0 -18px;
}
.star_10 {
background: url(stars.png) no-repeat 0 -36px;
}
.star_10 {
background: url(stars.png) no-repeat 0 -54px;
}
The vimscript is here:
" place functions here
function! SearchIncr(a1,a2,a3,a4,...)
" patn, repl, start, increment
let target = a:a1
let repl = a:a2
let startval = a:a3
let increment = a:a4
" 1st optional argument handles leading zeros
" process optional leading zero
if a:0 >= 1
let leadingz = a:1
else
" default to 0
let leadingz = 0
endif
" 2nd optional argument handles if target string goes before or after
" default is before
if a:0 == 2
" ideally set to 'after'
let repl_pos = a:2
else
let repl_pos = 'before'
endif
" inits
let l:incr = startval - increment
let lnum = a:firstline
" cycle though selection
while lnum <= a:lastline
" the FORMATTING string
if repl_pos == 'before'
let l:incrstring = '\=printf(''%s%0'. leadingz . 'd'',repl,l:incr)'
elseif repl_pos == 'after'
let l:incrstring = '\=printf(''%0'. leadingz . 'd%s'',l:incr,repl)'
else
"default to no leading zero and before placement
let l:incrstring = '\=printf(''%s%0d'',repl,l:incr)'
endif
" only increment counter when target matches
if match(getline(lnum),target) > 0
let l:incr = l:incr + increment
endif
" the search and replace
call setline(lnum,substitute(getline(lnum),target,
\ l:incrstring,'g'))
let lnum = lnum + 1
endwhile
endfunction
Any comments to improve on the above would be greatly appreciated!
Just using pure vim resources, no scripting:
:let c=10 | g/_\zs\d\+\ze/ s//\=c/ | let c-=1
:let c=0 | g/no-repeat 0 \zs\d\+/ s//\=c/ | let c-=18