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
Related
TLDR: How to find boxes that are lined up horizontally
Given I have the data from an image like this:
We can visually see that we have two lines:
Tare: 11700 kg 10:40:58 am 16-May
Gross: 21300 kg 12:49:34 pm 9-Aug
The data I have for each blue box shown in the image is:
Top
Left
Width
Height
Coordinates for each corner of the box (X, Y)
My main thought is to start from the top of my "grid" and loop through each value of y, and then group boxes where they share the largest amount of matching "y" values, but it seems very over the top for something that seems simple.
Unsure really where to go from here
Example data set
I was able to get boxes lined up using this bit of code (in JavaScript), it essentially finds the first "most top left" box, and then finds any boxes that "intersect" with a line that starts from the middle of that first box
We don't care what order we get the boxes in, so as long as we start with the most left on any line we are golden.
function getMostTopLeftBox(boxes) {
const sorted = boxes.slice()
.sort(
(a, b) => {
if (a.Left === b.Left) {
return a.Top < b.Top ? -1 : 1;
}
return a.Left < b.Left ? -1 : 1;
}
);
return sorted[0];
}
function getAlignedBoxesFromSet(boxes) {
const mostTopLeftBox = getMostTopLeftBox(boxes);
const line = mostTopLeftBox.Top + (mostTopLeftBox.Height / 2);
return boxes
.filter(({ Top, Height }) => Top < line && (Top + Height) > line)
.sort(({ Left: a }, { Left: b }) => a < b ? -1 : 1)
}
function getAlignedBoxes(boxes) {
let remaining = boxes;
const lines = [];
const next = () => {
const line = getAlignedBoxesFromSet(remaining);
lines.push(line);
remaining = remaining.filter(box => line.indexOf(box) === -1);
if (!remaining.length) {
return;
}
return next();
};
next();
return lines;
}
The above code with the data set provided above gives us this result
However, it doesn't account for slight angles on the boxes, for example this image:
Another example of different boxes, with senstive information removed:
You can see from the above that the values below should be considered to be on the same line:
Product: [type]
Num Of [type]: 0
[value]: [value]
I may make a new question for this, but part of the answer to this is to figure out the actual curve of a line, and not just assume that the median angle of all lines is the actual "curve" of the line, so if I was to start with the most left box, then progress to the second box, now I have two distinct lines that I would want to find the smoothed curve for, which I would then use to find the next box, as I find each box I would want to adjust this curve to find the complete line, I will investigate this one further, if anyone has any hints, please do mention it.
I've managed to solve this, with a variant of the code posted in the question.
Here is a code sandbox of the solution, I will do a full write up of this, but here it is for now: https://codesandbox.io/s/102xnl7on3
Here is an example of grouped boxes based on angled lines calculated from the angle of all horizontal lines, if all the boxes were to be straight, then the result would be the lines being straight as well, so it should work in all scenarios.
Here is also an example where the lines are straight:
You can see the lines from the box before intersecting with the next box, it does this each time until it can find a complete line of boxes (till no more line up), this works out better than using an average angle from the entire data set.
I would like to be able to generate a mathematical curve for the already found boxes and apply that to find the next box, but for now, using the previous box as the anchor works pretty well.
I was using Visjs and displaying rectanglar nodes with text. Some of the nodes can have a couple of lines of text so I added a heuristic algorithm to work out roughly where the line breaks should go to avoid very wide, single line chunks of text in very wide but very short nodes.
The trouble is, even with physics turned on, I still get overlapping nodes.
Is it possible to tell the layout engine that, under no circumstances (or physics models), should any two nodes overlap?
Well, check out the physics configuration example: as you can see, barnesHut solver has avoidOverlap property which prevents overlapping even when springConstant is equal to zero. Try this:
var options = {
"physics": {
"barnesHut": {
"springConstant": 0,
"avoidOverlap": 0.2
}
}
}
and tweak the constants to fit your needs (the example linked above is useful for that).
From its documentation:
Accepted range: [0 .. 1]. When larger than 0, the size of the node is taken into account. The distance will be calculated from the radius of the encompassing circle of the node for both the gravity model. Value 1 is maximum overlap avoidance.
To be noted, though: I've seen a recommendation to start with low values of avoidOverlap (like 0.1) to simplify the task for the solver. I can't recall where exactly I've read this.
I used levelSeparation to adjust the horizontal node distance, and nodeDistance to adjust the vertical node distance:
const options = {
layout: {
hierarchical: {
direction: 'LR',
sortMethod: 'directed',
levelSeparation: 300,
},
},
physics: {
hierarchicalRepulsion: {
nodeDistance: 140,
},
},
...
}
How can I make a very large skybox?
Example:
var skybox = BABYLON.Mesh.CreateBox("skyBox", 15000.0, this.scene);
The result is bad:
The first thing I suggest is to reduce the scale factor of your spaceship and planet models. It seems that having a SkyBox size larger than 10000 causes the ugly texture seams/tearing of the Skybox at particular camera angles and distances. So bring everything down in scale if possible to make more room inside the limits of the Skybox perimeter.
Next try this: set .infiniteDistance = true to keep the Skybox away from the camera, and also set .renderingGroupId = 0 on the Skybox. Lastly, set .renderingGroupId = 1 or more, on all the models and objects to help stop them from disappearing into thin air.
var skybox = BABYLON.MeshBuilder.CreateBox("skyBox", {size:10000.0},
this.scene);
skybox.infiniteDistance = true;
skybox.renderingGroupId = 0;
...and for models and sprite objects...
myModel.renderingGroupId = 1; /* greater than 0 */
These little tricks helped me to achieve a to-scale solar system simulation, but may not work in all cases.
Hello you need to increase camera.maxZ to a value larger than your skybox.
When loading a matrix consisting of 12 columns into R, and then printing it, the terminal window in OS X cuts the matrix in half, sort to speak, first showing all the rows with the initial 7 columns and then showing all the rows again with the remaining 5 columns. However, I would like it to display ll the columns, rather than dividing it up. How can I accomplish this?
Andrie's answer is good, though sometimes one uses a super duper monitor and 9999 is not enough. ;-)
Here's my function for setting the display width:
setWidth <- function (width = NULL)
{
if (is.null(width)) {
columns <- as.numeric(Sys.getenv("COLUMNS"))
if (!is.na(columns)) {
options(width = columns)
}
else {
options(width = 100)
}
}
else {
options(width = width)
}
}
This has been addressed previously, though.
So, to improve on just the changing of width, another trick that I recommend: change the number of digits used in numeric output - set options(digits = ...) to a smaller value. See ?options for more info.
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.