Using Stylus CSS preprocessor, I'm trying to write a mixin that will handle vendor-prefixing of the transition property and its transform value, and be able to accept multiple values.
Here's an example of the output I'm looking for:
-webkit-transition: opacity .2s linear .2s, -webkit-transform .2s linear .2s, left 0s linear .45s;
-moz-transition: opacity .2s linear .2s, -moz-transform .2s linear .2s, left 0s linear .45s;
-ms-transition: opacity .2s linear .2s, -ms-transform .2s linear .2s, left 0s linear .45s;
-o-transition: opacity .2s linear .2s, -o-transform .2s linear .2s, left 0s linear .45s;
transition: opacity .2s linear .2s, transform .2s linear .2s, left 0s linear .45s;
Note the vendor prefixes on both transition and transform.
While you can achieve this in stylus like this:
transition()
fix_transform($values, $vendor)
$new_values = ()
if match(',', '%s' % $values)
for $val in $values
if length($new_values) > 0
$new_values = $new_values, fix_transform($val, $vendor)
else
$new_values = fix_transform($val, $vendor)
else
for $val in $values
$new_val = $val
if $val == transform
$new_val = unquote($vendor + $new_val)
push($new_values, $new_val)
return $new_values
for $vendor in ('-webkit-' '-moz-' '-ms-' '-o-' '')
{$vendor}transiton: fix_transform(arguments, $vendor)
I'd recommend you not to use Stylus itself to add prefixes, but to use a specialized tool like autoprefixer for this.
There is actually a Stylus autoprefixer plugin — that would be the best to use with Stylus.
Related
The bounty expires in 2 days. Answers to this question are eligible for a +200 reputation bounty.
slevin wants to draw more attention to this question.
I use mapbox 2.10 and react 18.2. I have a mapbox fill-extrusion that gets a filter after a button click
map.current.setFilter('my-extrude', ['==',["id"] , 0] )
to show some extruded polygons.
In that layer I try to set a value for each polygon based on a property of the feature.
This doesnt work, I get Error: The layer 'my-extrude' does not exist in the map's style and cannot be filtered. probably because of the error in setting the opacity. If I set the opacity to a static number like 0.6, all works well.
What am I missing?
Thanks
map.current.addLayer({'id': 'my-extrude',
'type': 'fill-extrusion',
'source': 'my-extrude',
'paint': {
'fill-extrusion-color':[
'case',
['boolean', ['feature-state', 'hover'], false],'rgb(253, 255, 0)',
['boolean', ['feature-state', 'click'], false],'rgb(253, 255, 0)',
'rgb(253, 255, 72)'
] ,
'fill-extrusion-opacity':['get', 'customTop'],
'fill-extrusion-height': ['+',['to-number', ['get', 'customTop']] , ['to-number', ['get', 'customHeight']]],
'fill-extrusion-base': ['+',['to-number', ['get', 'customTop']], ['to-number', ['get', 'customBase']]]
}
});
it seems to me that instead of using 'feature-state' you should create a variable which will get the state of the map element on the page, and if the state is hover then give a static number for that case, and if the state is clicked then give a different static number.
Here most probably because you forgot to convert customTop to number just like you did for fill-extrusion-height and fill-extrusion-base and the error occures because fill-extrusion-opacity only accepts numbers between 0 and 1.
'fill-extrusion-opacity' : ['to-number', ['get', 'customTop']]
Note also when you use a variable to define fill-extrusion-opacity it is recommanded to set it with an interpolate expressions to make fill-extrusion-opacity always between 0 and 1.
Interpolate :
Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). The input may be any numeric expression (e.g., ["get", "population"]). Stop inputs must be numeric literals in strictly ascending order. The output type must be number, array, or color.
There are multiple ways to interpolate and the one needed here is the "linear" type :
Interpolates linearly between the pair of stops just less than and just greater than the input.
Inspired by this example from docs that uses the interpolate operator to define a linear relationship between zoom level and circle size using a set of input-output pairs
{
"circle-radius": [
"interpolate", ["linear"], ["zoom"],
// zoom is 5 (or less) -> circle radius will be 1px
5, 1,
// zoom is 10 (or greater) -> circle radius will be 5px
10, 5
]
}
with the same logic :
{
"fill-extrusion-opacity": [
"interpolate", ["linear"], ['to-number', ['get', 'customTop']],
// customTop is 0 (or less) -> fill-extrusion-opacity will be 0
0, 0,
// customTop is 1 (or greater) -> fill-extrusion-opacity will be 1
1, 1
]
}
The goal is to increase the length of a SCNBox such that it only grows in the positive-z direction.
This answer suggests playing with the pivot property.
However, the documentation for the pivot property is sparse on the SCNNode page, and there is nothing on the SCNBox page.
Can someone explain how the pivot property works?
Changing a node's pivot is conceptually the same as inserting an intermediate node between this node and its parent. This can be useful in different cases. One example is when the center of the node's geometry isn't where you expect it to be.
For instance if you have an SCNBox, it's bounding box is
min: (-0.5 * width, -0.5 * height, -0.5 * length)
max: (+0.5 * width, +0.5 * height, +0.5 * length)
center: (0.0, 0.0, 0.0)
If you want the length of the SCNBox to only increase in the positive Z axis, then what you want is
min: (-0.5 * width, -0.5 * height, 0.0)
max: (+0.5 * width, +0.5 * height, length)
center: (0.0, 0.0, +0.5 * length)
A geometry's bounding box will never change, but there are ways to arrange nodes and change their bounding boxes.
Solution 1: Intermediate node
One common solution when dealing with transforms is to use intermediate nodes to get a better understanding of how the transforms are applied.
In your case you will want to change the node hierarchy from
- parentNode
| - node
| * geometry
| * transform = SCNMatrix4MakeScale(...)
to
- parentNode
| - intermediateNode
| * transform = SCNMatrix4MakeScale(...)
| | - node
| | * geometry
| | * transform = SCNMatrix4MakeTranslation(0, 0, +0.5 * length)
With this new hierarchy, the center of the bounding box of node is still (0.0, 0.0, 0.0), but the center of the bounding box of intermediateNode is (0.0, 0.0, +0.5 * length).
By scaling intermediateNode instead of node you'll obtain the wanted result.
Solution 2: Pivot
It turns out that's exactly what the pivot property does:
node.pivot = SCNMatrix4MakeTranslation(0, 0, -0.5 * length);
Once you have mentally figured out the transform of the intermediate node, simply set its inverse to the pivot property.
You can find more information about the pivot property here: https://developer.apple.com/reference/scenekit/scnnode/1408044-pivot
This is very similar to Core Animation's anchorPoint property on CALayer, except that in Core Animation the anchor point is specified as relative to the layer's bounding box (goes from 0 to 1 as a percentage of the layer's width and height), while in SceneKit it's absolute.
Say you have a box created like this:
SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
The pivot point will be in the center of that box, you now want to move it to one of the edges. This can be done by translating the pivot node by 0.5. (This is half the width of the box or the distance between the center and the edge.)
boxNode.pivot = SCNMatrix4MakeTranslation(0, 0, -0.5)
The pivot point will now be located at center X, center Y, and zero Z of the object. If you now scale the box it will only grow in the positive Z direction.
Sounds like you want to increase the length of the SCNBox(a geometry). So you can simply increase the length property. The answer you mentioned is about the pivot property. As you can see from the doc:
The pivot point for the node’s position, rotation, and scale.
For example, by setting the pivot to a translation transform you can position a node containing a sphere geometry relative to where the sphere would rest on a floor instead of relative to its center.
Following code
for $i in (1..81)
.block:nth-child({$i})
transition transform 500ms ease $i\s
will be compiled to
.block:nth-child(1) {
transition: transform 500ms ease 1 s;
}
......
But that space between number and seconds is redundant!
How can I remove it?
One possible approach:
for $i in (1..81)
.block:nth-child({$i})
transition transform 500ms ease 1s * $i
That's actually quite similar to the example given in Selector Interpolation section of Stylus documentation.
You can use the unit() function:
for $i in (1..81)
.block:nth-child({$i})
transition transform 500ms ease unit($i, 's')
I'm trying to mimic a graphic print trend in which you highlight headers. Pretty simple.
I need to add little padding to the text to make it more pleasing to the eye and readable.
Problem arises when text is wrapped - the padding only affects the first line making it appear as if the header is indented. Making the element (anchor) block-level fixes this, but then the whole element is highligtet and not just the text.
Can this be done using only css? It would be loathsome having to add javascript for such a simple thing.
Tjek the website here. Most of the headers a fairly short why the problem doesn't occur.
CSS:
h1 {
background:#ff0;
color:#000;
box-shadow:0.2em 0 0 #ff0, -0.2em 0 0 #ff0;
-moz-box-shadow:0.2em 0 0 #ff0, -0.2em 0 0 #ff0;
-webkit-box-shadow:0.2em 0 0 #ff0, -0.2em 0 0 #ff0;
}
Where #ff0 is the color you want the background to be.
Yes, this can be done using only CSS. Here's a post on CSS-Tricks detailing several methods for handling this issue.
One of them involves using box-shadow to apply the padding effect. Simply set two shadows, each with a horizontal offset of your desired padding along with the color of the highlight:
.highlight {
-webkit-box-shadow: 10px 0 0 orange,
-10px 0 0 orange;
-moz-box-shadow: 10px 0 0 orange,
-10px 0 0 orange;
box-shadow: 10px 0 0 orange,
-10px 0 0 orange;
}
Demo
I need to resize and crop an image to a specific width and height. I was able to construct a method that will create a square thumbnail, but I'm unsure on how to apply this, when the desired thumbnail is not square.
def rescale(data, width, height):
"""Rescale the given image, optionally cropping it to make sure the result image has the specified width and height."""
from google.appengine.api import images
new_width = width
new_height = height
img = images.Image(data)
org_width, org_height = img.width, img.height
# We must determine if the image is portrait or landscape
# Landscape
if org_width > org_height:
# With the Landscape image we want the crop to be centered. We must find the
# height to width ratio of the image and Convert the denominater to a float
# so that ratio will be a decemal point. The ratio is the percentage of the image
# that will remain.
ratio = org_height / float(org_width)
# To find the percentage of the image that will be removed we subtract the ratio
# from 1 By dividing this number by 2 we find the percentage that should be
# removed from each side this is also our left_x coordinate
left_x = (1- ratio) / 2
# By subtract the left_x from 1 we find the right_x coordinate
right_x = 1 - left_x
# crop(image_data, left_x, top_y, right_x, bottom_y), output_encoding=images.PNG)
img.crop(left_x, 0.0, right_x, 1.0)
# resize(image_data, width=0, height=0, output_encoding=images.PNG)
img.resize(height=height)
# Portrait
elif org_width < org_height:
ratio = org_width / float(org_height)
# crop(image_data, left_x, top_y, right_x, bottom_y), output_encoding=images.PNG)
img.crop(0.0, 0.0, 1.0, ratio)
# resize(image_data, width=0, height=0, output_encoding=images.PNG)
img.resize(width=witdh)
thumbnail = img.execute_transforms()
return thumbnail
If there is a better way to do this please let me know. Any help would be greatly appreciated.
Here's a diagram explaining the desired process.
Thanks,
Kyle
I had a similar problem (your screenshot was very useful). This is my solution:
def rescale(img_data, width, height, halign='middle', valign='middle'):
"""Resize then optionally crop a given image.
Attributes:
img_data: The image data
width: The desired width
height: The desired height
halign: Acts like photoshop's 'Canvas Size' function, horizontally
aligning the crop to left, middle or right
valign: Verticallly aligns the crop to top, middle or bottom
"""
image = images.Image(img_data)
desired_wh_ratio = float(width) / float(height)
wh_ratio = float(image.width) / float(image.height)
if desired_wh_ratio > wh_ratio:
# resize to width, then crop to height
image.resize(width=width)
image.execute_transforms()
trim_y = (float(image.height - height) / 2) / image.height
if valign == 'top':
image.crop(0.0, 0.0, 1.0, 1 - (2 * trim_y))
elif valign == 'bottom':
image.crop(0.0, (2 * trim_y), 1.0, 1.0)
else:
image.crop(0.0, trim_y, 1.0, 1 - trim_y)
else:
# resize to height, then crop to width
image.resize(height=height)
image.execute_transforms()
trim_x = (float(image.width - width) / 2) / image.width
if halign == 'left':
image.crop(0.0, 0.0, 1 - (2 * trim_x), 1.0)
elif halign == 'right':
image.crop((2 * trim_x), 0.0, 1.0, 1.0)
else:
image.crop(trim_x, 0.0, 1 - trim_x, 1.0)
return image.execute_transforms()
You can specify both height and width parameters to resize -- it will not change the aspect ratio (you cannot do that with GAE's images module), but it will ensure that each of the two dimensions is <= the corresponding value you specify (in fact, one will be exactly equal to the value you specify, the other one will be <=).
I'm not sure why you're cropping first and resizing later -- it seems like you should do things the other way around... resize so that as much of the original image "fits" as is feasible, then crop to ensure exact resulting dimension. (So you wouldn't use the original provided values of height and width for the resize -- you'd scale them up so that none of the resulting image is "wasted" aka "blank", if I understand your requirements correctly). So maybe I'm not understanding exactly what you require -- could you provide an example (URLs to an image as it looks before the processing, to how it should look after the processing, and details of the parameters you'd be passing)?