How to Generate Placeholders in Stylus - css

I'm looking to generate placeholders and variables that can change depending on configured proportions such as the following:
$small-margin-top
$large-margin-top
$small-padding-bottom
Where each placeholder applies the corresponding, generated variable to the rule:
$small-margin-top
margin-top $marginsmall
$large-margin-top
margin-top $marginLarge
$small-padding-bottom
margin-bottom $marginSmall
I have statically defined the variables for now:
/* Margin */
$margin = 1rem
$marginsmall = $margin / $multiplier
$marginlarge = $margin * $multiplierLarge
$marginmini = $marginSmall / $multiplierLarge
But I get an error:
TypeError: expected "name" to be a string, but got ident:marginmini
properties = margin padding
proportions = mini small medium large
directions = top left bottom right
for property in properties
for proportion in proportions
for direction in directions
${property}-{direction}-{proportion}
{property}-{direction} lookup(property + proportion)
How can I generate placeholders for my proportions variable, such that the generated placeholders may be extended later (#extend $margin-large)?
EDIT: here is the working solution

The lookup bif accepts a string, and you are passing an ident (margin, padding, etc. without quotes). You can convert them to string by using concatenation. Also, you miss a $ sign:
properties = margin padding
proportions = mini small medium large
directions = top left bottom right
for property in properties
for proportion in proportions
for direction in directions
${proportion}-{property}-{direction}
{property}-{direction} lookup('$' + property + proportion)

Related

How to do a random border radius scss

I want to add the unit after a random($limit: 100) i want in the css : border-radius: <the random number>%
You can multiply the result from random() by 1% (or any other unit you may want) to append the unit. The outer parenthesis is a sass feature, so those type of calculations only work with alike-units or unitless + alike-units.
border-radius: (random($limit: 50) * 1%);

iText7 large table autoLayout()

According to the docs
public Table(int numColumns,
boolean largeTable)
Constructs a Table with specified number of columns. The final column widths depend on selected table layout. Since 7.0.2 table layout algorithms were introduced. Auto layout is default, except large tables. For large table fixed layout set implicitly. Since 7.1 table will have undefined column widths, that will be determined during layout. In oder to set equal percent width as column width, use UnitValue.createPercentArray(int)
I render a large table using https://developers.itextpdf.com/examples/tables/clone-large-tables
Is there a way to define autoLayout? Maybe after adding the first row, get the cell widths and set them on the table, but that doesn't seem possible, because the column widths are null because I am using the constructor with number of columns.
Or adding some sort of autoLayout when end page is reached.
I don't want to define the widths for the columns because we have lots of tables.
First of all I would like to mention that auto layout requires the content of the whole table. The content is used when calculating the column widths. But you are using large table, which probably means you have a lot of data and you don't want to keep everything in memory (if that's not the case, just don't use large tables).
Thus, all you can do is calculate an approximation of the automatic column widths given some initial cells. Basically, it is possible to implement your first idea, however, it takes some code to be written. But if you have very different content in cells across different rows (e.g. images vs inner tables vs some text), then this method might not work very well because as I said, to estimate column widths well you need all the content.
Please also bear in mind that this approach is quite dirty and might not work for some corner cases. But it does solve the goal and frees you of the necessity to define column widths.
To describe the solution in a few words, we take cells of several initial rows, add them to a temporary table and layout it (estimate positions etc), without actually drawing it anywhere. Then we extract the cell widths from the layout step information and can use them for the large table constructor.
The method estimating column widths looks like this:
private UnitValue[] estimateWidths(Document document, Cell[][] cells) {
int numOfColumns = cells[0].length;
Table table = new Table(numOfColumns);
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
table.addCell(cells[i][j]);
}
}
LayoutContext context = new LayoutContext(document.getRenderer().getCurrentArea().clone());
TableRenderer tableRenderer = (TableRenderer)table.createRendererSubTree();
LayoutResult result = tableRenderer.setParent(document.getRenderer()).layout(context);
if (result.getStatus() == LayoutResult.PARTIAL) {
tableRenderer = (TableRenderer) result.getSplitRenderer();
}
UnitValue[] widths = new UnitValue[numOfColumns];
List<IRenderer> subList = tableRenderer.getChildRenderers().subList(0, numOfColumns);
for (int i = 0; i < subList.size(); i++) {
IRenderer cell = subList.get(i);
widths[i] = UnitValue.createPointValue(cell.getOccupiedArea().getBBox().getWidth());
}
return widths;
}
So assuming you have a Cell[][] cells array of cells for initial couple of rows (can be one row as well, but the more the better), where cells[i][j] refers to the cell at row i and column j, you can create your large table like this:
Table table = new Table(estimateWidths(doc, cells), true);
But don't forget to explicitly add cells from cells array to the large table before adding new content.

How to add/sub to a dynamic variable?

I have a problem with the following code:
#viewport-large: 1440px;
#viewport-medium: 1366px;
#viewport-small: 1280px;
#type: medium;
#setting: ~"#{viewport-#{type}}";
#value: (#setting + 1); // here can't add 1
It will show an error message in the LESS compiler saying: "Operation on an invalid type".
Can anyone tell me why this is the case? What should I do?
The output of Less' CSS escape function (e() or ~"") is a string and you can't add a number to it. This is why the compiler reports Operation on invalid type.
So, instead of doing it that way make use of the double resolution (##) like in the below code block:
#viewport-large: 1440px;
#viewport-medium: 1366px;
#viewport-small: 1280px;
#type: medium;
#setting: "viewport-#{type}"; /* this won't resolve into 1336px as yet */
#value: ##setting + 1px; /* resolution to 1336px + addition happens here */
In this method, we just form the variable name and set it to the #setting variable (instead of setting a actual px value) and so the real px value's type remains unpolluted. In the next line when we use the double #, Less compiler would try to fetch the value that is held by the variable whose name is same as the value of #setting variable and immediately sum 1px to it instead of converting it to a String.
Note: If you have the Strict Math option (--strict-math) enabled then the addition operation must be wrapped inside extra braces like below. Else, it would plainly output a concatenated value like 1366px + 1px instead of performing the addition and outputting 1367px.
#value: (##setting + 1px);
The --strict-math setting is disabled by default but some of your projects could have enabled it.

Mathematically scale large elements lesser then small elements

10 elements with the class xxx have different widths and heights. Putting transform: scale(1.1) enlarges the big ones clearly but the small ones barely show difference. This is bad UX. The mathematical question is how to make the bigger elements scale less then the smaller ones:
width 10 should get scale 1.1
width 5 should get scale 1.2
How can i mathematically solve this?
The question lacks context and details, so it is hard to give a generally meaningful answer. However, the given examples indicate the following solution:
x_new = 1 + 1/x_old
Where x_old is the input value, i.e. 10 or 5.
Using logarithmic scaling instead of just 1/x_old might be another option, depending on the context.
To illustrate the scenarios i made these pens:
non logarithmic scale: http://codepen.io/anon/pen/bwRVpj
logarhitmic scale: http://codepen.io/anon/pen/VKWLJK
var inlineStyle = ''
var divs = document.getElementsByTagName('div')
var len = divs.length
while(len--) {
var elWidth = divs[len].offsetWidth
var scale = 1+9/elWidth
inlineStyle += `#${divs[len].id}:hover {
transform: scale(${scale})
}`
}
document.getElementById('lolStyle').innerHTML = inlineStyle

Flex Charts: Can you use a minimum/maximum point from an IAxis for Cartesian Data Canvas to draw the entire width of the chart?

I have a chart with a DateTime axis as my horizontal and a Linear Axis for my vertical inside a Adobe Flex Line Chart. I want to use a Cartesian Data Canvas as a background element and draw custom set of background graphics mostly rectangles. When I have more than a single data point, the graphics work perfectly since they are supposed to span the width of the entire chart.
When I have only a single data point, however, I can't seem to get the rectangles to draw. Since I want my rectangles to span the entire width of the chart, I was thinking that I could get the x-coordinates from my axis, but this isn't working.
var canvasWidth:Number = chtCanvas.width;
var canvasHeight:Number = chtCanvas.height;
var minPt:Array;
var maxPt:Array;
var minPtDate:Date;
var maxPtDate:Date;
var minPtComplete:Point;
var maxPtComplete:Point;
// This works fine when there is more than 1 data point
minPt = chtCanvas.localToData(new Point(0, 0));
maxPt = chtCanvas.localToData(new Point(canvasWidth,canvasHeight));
//This does return a date object, but wont draw below
minPtDate = axisDate.minimum;
maxPtDate = axisDate.maximum;
//This returns NaN for the x
minPtComplete = chtCanvas.dataToLocal(minPtDate, axisSalary.minimum);
maxPtComplete = chtCanvas.dataToLocal(maxPtDate, axisSalary.maximum);
// Also tried this. Also returns NaN for the x value
//minPtComplete = chtCanvas.dataToLocal(axisDate.minimum, axisSalary.minumum);
//maxPtComplete = chtCanvas.dataToLocal(axisDate.maximum, axisSalary.maximum);
My actual drawing method is as follows:
// Tried this, works with points >2, does not draw with single data point
chtCanvas.drawRect(minPt[0], detail[i].MaxValue, maxPt[0], detail[i].MinValue);
//tried this, no effect with single point
//chtCanvas.drawRect(minPtDate, detail[i].MaxValue, maxPtDate, detail[i].MinValue);
// Tried this, no effect with single point
//chtCanvas.drawRect(minPtDate, minPt[1], maxPtDate, detail[i].MinValue);
// Tried this also
//chtCanvas.drawRect(minPtComplete.x, detail[i].MaxValue, maxPtComplete.x, detail[i].MinValue);
In this example, detail is an array collection of salary values and Im using the data value in the array to determine the vertical bounds of my rectangles.
I need to draw the rectangles the entire width of the chart (even when there is only a single data point). Thanks
Thanks to Heikki for his help. The following code works to use the axis values to draw on your Cartesian Data Canvas:
chtCanvas.drawRect(axisDate.minimum as Date, axisSalary.maximum, axisDate.maximum as Date, axisSalary.minimum);
Casting the values as Date really helped. The rest of the code used above is unecessary.
One thing to note, I was using a DateFormatter to format the date values from my data. What I didn't consider was that when using a DateTimeAxis, Flex will automatically add in extra dates to display on the axis. In my case, I was using a custom parse function to create MY points, but wasnt considering the points Flex was creating and also passing to my parse function (Therefore, they were not getting parsed correctly). Once I corrected this, the values laid out correctly in the case of multiple data points. I'm still having a bit of an issue with single data points and them not filling the chart entirely, but they are now drawing.
UPDATE:
Although there are signs of life, the minimum and maximum are still not drawing the entire width of the chart in some cases depending on the dataUnits and labelUnits combination.
UPDATE #2: SOLVED
Ok, so the axis does work as minimum/maximum values for the Cartesian Data Canvas but there is something important to remember. For a single point (and probably for multiple points as well, I just couldnt visually see the difference), when using a custom DateTimeAxis parse function such as what was in the Adobe Flex ASDoc tutorials:
private function axisDateParseFunction(item:String):Date
{
var inputDate:String = item;
inputDate = fmtDate.format(inputDate);
var newDate:Date = new Date();
if(inputDate)
{
var a:Array = inputDate.split('/');
newDate.fullYear = a[2];
newDate.month = a[0] - 1;
newDate.date = a[1];
newDate.hours = 0;
newDate.hoursUTC = 0;
newDate.minutes = 0;
newDate.minutesUTC = 0;
newDate.seconds = 0;
newDate.secondsUTC = 0;
newDate.milliseconds = 0;
newDate.millisecondsUTC = 0;
}
return newDate;
}
You MUST remember to set the UTC values as shown above also. Since the DateTimeAxis uses date AND time, when you create new Date objects, their time values also get set to the local system time. Remember to set those values to zero also or you will get points that dont exactly line up with your axis labels.

Resources