SCSS for each loop with Multiple Variables with decimal values - loops

I'm having trouble with a SASS #each loop with multiple variables using decimals. I can get it to work on a basic level but want to add decimals, which throws me errors.
For example..
$columns: 100, 25, 33;
#each $proportion in $columns {
.col_#{nth($proportion, 1)} {
width: percentage($proportion/100);
}
}
... will successfully compile to...
.col_100 {
width: 100%;
}
.col_25 {
width: 25%;
}
.col_33 {
width: 33%;
}
However, trying to add a decimal to the variable list throws me an error. For example how can I get this to to work...
$columns: 100, 25, 33.333;

You could round the value for the class name:
#each $proportion in $columns {
.col_#{floor(nth($proportion, 1))} {
width: percentage($proportion/100);
}
}
Output:
.col_100 {
width: 100%;
}
.col_25 {
width: 25%;
}
.col_33 {
width: 33.333%;
}

Related

SCSS for loop: mix variable with index

In the following situation, I would like to combine variables with the loop index (in SCSS):
Predefined variables
$item-width-1: 400px;
$item-height-1: 340px;
$item-spacing-1: 40px;
$item-width-2: 200px;
$item-height-2: 440px;
$item-spacing-2: 100px;
$item-width-3: 300px;
$item-height-3: 240px;
$item-spacing-3: 60px;
For loop:
#for $i from 2 through 3 {
&:nth-child(#{$i}) {
.image { width: $item-width-#{$i}; height: $item-height-#{$i}; bottom: $item-spacing-#{$i}; }
.content { transform: translate(calc(#{$item-width-#{$i}} + 40px), 0); bottom: $item-spacing-#{$i}; }
.line { height: 108px + $item-spacing-#{$i}; left: $item-width-#{$i} / 2; }
&.active { width: $item-width-#{$i} + ($content-width + 80px); }
}
}
But it shows the following error:
Any ideas on how I could fix this?
Thank you in advance!

How to write a loop function or mixin with variables in less.js for DRY

Is there any efficient way to write this code with less.js:
I've got already 3 variables colors : #vert, #violet and #orange
li {
&:nth-child(1) {
background: #vert;
&:hover,
&.open {
>.dropdown-menu li {
background: #vert;
}
}
}
&:nth-child(2) {
background: #violet;
&:hover,
&.open {
>.dropdown-menu li {
background: #violet;
}
}
}
&:nth-child(3) {
background: #orange;
&:hover,
&.open {
>.dropdown-menu li {
background: #orange;
}
}
}
}
I thought of a mixin, but I'm not writing well: Any help please ?
.colored-menu(#number, #color) {
&:nth-child(#number) {
background: #color;
&:hover,
&.open {
>.dropdown-menu li {
background: #color;
}
}
}
}
and calling it like this:
.colored-menu(1,#vert);
.colored-menu(2,#violet);
.colored-menu(3,#orange);
You can use your approach with some edits:
// mixin
.colored-menu(#number; #color) { // the docs recommends semi-colons instead of commas
&:nth-child(#{number}) { // variable requires curly brackets for interpolation
background: #color;
&:hover,
&.open {
> .dropdown-menu li {
background: #color;
}
}
}
}
// ruleset
li {
.colored-menu(1; #vert);
.colored-menu(2; #violet);
.colored-menu(3; #orange);
}
Also, consider using the each list function:
// list
#colors: #vert, #violet, #orange;
// ruleset
li {
each(#colors, {
&:nth-child(#{index}) {
background: #value;
&:hover,
&.open {
> .dropdown-menu li {
background: #value;
}
}
}
});
}
The output from both approaches are the same (in this instance).

How to make different color of markers in amchart

import React, { Component } from 'react';
import * as am4core from "#amcharts/amcharts4/core";
// import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
import * as am4maps from "#amcharts/amcharts4/maps";
import am4geodata_worldLow from "#amcharts/amcharts4-geodata/indiaLow";
import am4themes_frozen from "#amcharts/amcharts4/themes/frozen";
import './style.css'
am4core.useTheme(am4themes_frozen);
class WorldMap extends Component {
constructor(props){
super(props);
this.state = {
bubble:{}
}
}
componentDidMount() {
let chart = am4core.create("worldmap", am4maps.MapChart);
chart.geodata = am4geodata_worldLow;
chart.projection = new am4maps.projections.Miller();
let polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
polygonSeries.exclude = ["AQ"];
polygonSeries.useGeodata = true;
let polygonTemplate = polygonSeries.mapPolygons.template;
polygonTemplate.tooltipText = "{name}";
polygonTemplate.fill = chart.colors.getIndex(0).lighten(0.5);
let hs = polygonTemplate.states.create("hover");
hs.properties.fill = chart.colors.getIndex(0);
let imageSeries = chart.series.push(new am4maps.MapImageSeries());
imageSeries.mapImages.template.propertyFields.longitude = "longitude";
imageSeries.mapImages.template.propertyFields.latitude = "latitude";
imageSeries.data = [ {
"zoomLevel": 5,
"scale": 0.5,
"title": "Odisha",
"latitude": 20.29,
"longitude": 85.82,
}, {
"zoomLevel": 5,
"scale": 0.5,
"title": "Karnataka",
"latitude": 12.99,
"longitude": 77.71,
}, {
"zoomLevel": 5,
"scale": 0.5,
"title": "Andhra Pradesh",
"latitude": 14.99,
"longitude": 77.71,
}
];
chart.events.on( "mappositionchanged", updateCustomMarkers );
function updateCustomMarkers( event ) {
imageSeries.mapImages.each(function(image) {
if (!image.dummyData || !image.dummyData.externalElement) {
image.dummyData = {
externalElement: createCustomMarker(image)
};
}
let xy = chart.geoPointToSVG( { longitude: image.longitude, latitude: image.latitude } );
image.dummyData.externalElement.style.top = xy.y + 'px';
image.dummyData.externalElement.style.left = xy.x + 'px';
});
}
// this function creates and returns a new marker element
function createCustomMarker( image ) {
let chart = image.dataItem.component.chart;
// create holder
let holder = document.createElement( 'div' );
holder.className = 'map-marker';
holder.title = image.dataItem.dataContext.title;
holder.style.position = 'absolute';
// maybe add a link to it?
if ( undefined != image.url ) {
holder.onclick = function() {
window.location.href = image.url;
};
holder.className += ' map-clickable';
}
// create dot
let dot = document.createElement( 'div' );
dot.className = 'dot';
holder.appendChild( dot );
// create pulse
let pulse = document.createElement( 'div' );
pulse.className = 'pulse';
holder.appendChild( pulse );
// append the marker to the map container
chart.svgContainer.htmlElement.appendChild( holder );
return holder;
}
}
componentWillUnmount() {
if (this.chart) {
this.chart.dispose();
}
}
render() {
return (
<div id="worldmap" style={{ width: "100%", height: "500px" }}></div>
);
}
}
export default WorldMap;
Here i am using amcharts with React.
Please have a look into my screenshot.
I want exact like this and it is coming but ,
the marker those are coming yellow i wants to change some markers to red and green.
Is it possible to do that ??
I have shared the screenshot below please have a look.
i found it from amcharts map demos
So, React is irrelevant here. The demo you've copied is our "Custom HTML Elements as Map Markers" demo.
You've shared some of the JavaScript code, but since these markers are pure HTML, they are styled via CSS. Here's the CSS from the demo:
#chartdiv {
width: 100%;
height: 500px;
overflow: hidden;
}
.map-marker {
/* adjusting for the marker dimensions
so that it is centered on coordinates */
margin-left: -8px;
margin-top: -8px;
}
.map-marker.map-clickable {
cursor: pointer;
}
.pulse {
width: 10px;
height: 10px;
border: 5px solid #f7f14c;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
background-color: #716f42;
z-index: 10;
position: absolute;
}
.map-marker .dot {
border: 10px solid #fff601;
background: transparent;
-webkit-border-radius: 60px;
-moz-border-radius: 60px;
border-radius: 60px;
height: 50px;
width: 50px;
-webkit-animation: pulse 3s ease-out;
-moz-animation: pulse 3s ease-out;
animation: pulse 3s ease-out;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
animation-iteration-count: infinite;
position: absolute;
top: -20px;
left: -20px;
z-index: 1;
opacity: 0;
}
/* keyframe stuff here */
This is what's responsible for the yellow background color:
.pulse {
/*...*/
background-color: #716f42;
/*...*/
}
If you want to change background colors, it can be done via the background-color declaration on the .pulse div. You can add more CSS classes (after .pulse), e.g.
.pulse--red {
background-color: red;
}
.pulse--green {
background-color: green;
}
Or you can pass color keys in your data, e.g.
{
"zoomLevel": 5,
"scale": 0.5,
"title": "Karnataka",
"latitude": 12.99,
"longitude": 77.71,
"color": "red"
}
I am not sure what your logic would be for changing colors, but let's say we want to change every 2nd of 3 markers to red and every 3 of 3 markers to green, here's an updated createCustomMarker function that uses color from data and adds additional pulse--* classes:
// keep a counter for fuzzy color logic
var markers = 0;
// this function creates and returns a new marker element
function createCustomMarker( image ) {
var chart = image.dataItem.component.chart;
// create holder
var holder = document.createElement( 'div' );
holder.className = 'map-marker';
holder.title = image.dataItem.dataContext.title;
holder.style.position = 'absolute';
// maybe add a link to it?
if ( undefined != image.url ) {
holder.onclick = function() {
window.location.href = image.url;
};
holder.className += ' map-clickable';
}
// create dot
var dot = document.createElement( 'div' );
dot.className = 'dot';
holder.appendChild( dot );
// create pulse
var pulse = document.createElement( 'div' );
pulse.className = 'pulse';
// logic for switching colors
switch (markers) {
case 1:
pulse.className += " pulse--red";
++markers;
break;
case 2:
pulse.className += " pulse--green";
markers = 0;
break;
default:
++markers;
break;
}
// or apply color via data
var color = image.dataItem.dataContext.color;
if (color) {
// pulse.setAttribute('style', 'background-color: ' + color + ' !important');
// or
pulse.style.backgroundColor = color;
}
holder.appendChild( pulse );
// append the marker to the map container
chart.svgContainer.htmlElement.appendChild( holder );
return holder;
}
Here's a fork of our demo with the above:
https://codepen.io/team/amcharts/pen/6fad5b27c1456e6288032c5aaaae0c3e

How to use a stylus variable in a selector

I would like to do something like this:
for $num in (1..100)
:scope[md="$num"]
width: $num + '%'
but it gives me this
:scope[md="$num"] {
width: 1%;
}
:scope[md="$num"] {
width: 2%;
}
How can I make $num be replaced in the selector as well?
You have to use interpolation. In the comment Jcl has made a little mistake by not remove the quotes:
STYLUS
for $num in (1..100)
:scope[md={$num}]
width: $num + '%'
OUTPUT
:scope[md=1] {
width: 1%;
}
:scope[md=2] {
width: 2%;
}
:scope[md=3] {
width: 3%;
}
...
If you want the output with quotes you can escape like this:
:scope[md=\"{$num}\"]

Grouping Selectors inside of a loop using Sass

The Issue
I'm currently in a pickle. I need to group selectors inside of a Sass loop. I've tried many different ways to go about doing this such as:
body {
$store: null;
#for $i from 1 through 10 {
$store: append($store, ".offset-by-#{$i}", comma);
}
// produces content: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
#each $j in $store {
$store: unquote($j);
}
// produces .offset-by-10
}
What I'm trying to accomplish using pure Sass (no Ruby) is the following:
.offset-by-1,
.offset-by-2,
.offset-by-3,
...
.offset-by-10 { foo: bar; }
If you are a Sass god then please give me an idea of what to do here. If this is an inherent limitation of the meta-language then let me know about that too!
Considerations
I can't use anything other than a mixin to accomplish this because functions are expected to be used on a property value. Mixins, on the other hand allow the production of entire blocks of code.
Keep it simple, soldier!
%foo {
foo: bar; }
#for $i from 1 through 10 {
.offset-by-#{$i} {
#extend %foo; }}
UPD You can also have individual styles with this approach:
%foo {
foo: bar; }
#for $i from 1 through 10 {
.offset-by-#{$i} {
#extend %foo;
margin-left: 50px * $i; }}
Which results in the following CSS:
.offset-by-1, .offset-by-2, .offset-by-3, .offset-by-4, .offset-by-5, .offset-by-6, .offset-by-7, .offset-by-8, .offset-by-9, .offset-by-10 {
foo: bar; }
.offset-by-1 {
margin-left: 50px; }
.offset-by-2 {
margin-left: 100px; }
.offset-by-3 {
margin-left: 150px; }
.offset-by-4 {
margin-left: 200px; }
.offset-by-5 {
margin-left: 250px; }
.offset-by-6 {
margin-left: 300px; }
.offset-by-7 {
margin-left: 350px; }
.offset-by-8 {
margin-left: 400px; }
.offset-by-9 {
margin-left: 450px; }
.offset-by-10 {
margin-left: 500px; }
Have you tried something like this:
#mixin createNumbered($num, $className){
#for $i from 1 through $num {
.#{$className}-#{$i} {
#content;
}
}
}
#include createNumbered(10, 'foo-bar'){
color: white;
}
Updated:
#mixin createNumbered($num, $className){
$foo : '';
#for $i from 1 through $num {
$foo : $foo + '.' + $className + '-' + $i + ', ';
}
#{$foo} {
#content;
}
}
#include createNumbered(10, 'foo-bar'){
color: white;
}
This is likely overkill for what you need, but I needed to be able to add :last-child onto the class list. I built this on Clark Pan's Answer:
#mixin group-classes($start, $stop, $step, $selector, $selector-suffix, $property, $value) {
$selector-list: '';
$i: $start;
#while $i <= $stop {
$comma: ', ';
#if $i == $stop {
$comma: '';
}
$selector-list: $selector-list + $selector + '-' + $i + $selector-suffix + $comma;
$i: $i + $step;
}
#{$selector-list} {
#{$property}: #{$value}
}
}
And then to use it:
#include group-classes(1, 3, 1, '.e > .g', ':last-child', 'margin', 0);
Result:
.e > .g-1:first-child,
.e > .g-2:first-child,
.e > .g-3:first-child {
margin:0!important;
}

Resources