Direct linear transformation in CSS - css

Is it possible to do a DLT in CSS? If so, how is this accomplished? I can't think of a way using just transform: matrix... If this is not possible, what would be an alternative approach?
The particular effect I'm trying to achieve is laying out divs in a way similar to how Safari does this:

Here is a very rough and non-generic answer to your request. http://jsfiddle.net/3t5SM/
You could easily extend it to get a generic much better solution.
in my CSS,
#id1, #id4, #id7{
-webkit-transform: rotateY(40deg);
}
#id3, #id6, #id9{
-webkit-transform: rotateY(-40deg);
}
#id2, #id5, #id8{
-webkit-transform: scale(0.94);
}
the basic idea is to create a style for each column (here i'm calling the id's but again, it would be better to have a style for each column and define the columns as .left, .middle, .right, etc)
I'll update my post tonight if I have the time to go into the details :)
EDIT: as promise, here is a little better version. Now it is much more generic and depending on the size of your window, you'll get the right number of cubes. It is still far from being perfect (you could play with the size of the cubes in order to get a better depth feeling), but in general you see that it is possible, even dynamically :)
here is the fiddle: http://jsfiddle.net/P84qd/4/
To go a little into the details of the javascript:
function dispatch(){
var sizeOfImg = 150;
var windowWith = document.body.offsetWidth;
var widthRest = windowWith%sizeOfImg;
var nbSquareRow = Math.floor(windowWith/sizeOfImg);
dlt(nbSquareRow);
var marginVal = widthRest/(nbSquareRow+1);
var lineout = document.getElementById('lineout');
lineout.style.paddingLeft = marginVal+'px';
lineout.style.paddingTop = marginVal+'px';
var square = document.getElementsByTagName('div');
for(var i=0, length = square.length;i<length; i++){
if(square[i].className === 'square'){
square[i].style.marginRight = marginVal+'px';
square[i].style.marginBottom = marginVal+'px';
}
}
}
dispatch();
window.onresize = function(e){dispatch();};
function dlt(nbSquareRow){
var maxRotatDeg = 40;
var isEven=true;
if(nbSquareRow%2 == 0){
var unityRotatDeg = maxRotatDeg/(nbSquareRow/2);
}else{
var unityRotatDeg = maxRotatDeg/((nbSquareRow-1)/2);
isEven = false;
}
var middle = Math.floor(nbSquareRow/2);
var mySquares = document.getElementsByTagName('div');
for(var j=0, sqleng = mySquares.length;j<sqleng; j++){
if(mySquares[j].className == 'square'){
var colNumb = (parseInt(mySquares[j].id)-1)%nbSquareRow;
var myMultiplier = (middle-colNumb);
if(isEven && myMultiplier<=0){
myMultiplier--;
}
mySquares[j].style.webkitTransform = 'rotateY('+(unityRotatDeg*myMultiplier)+'deg)';
}
}
}
The dispatch function is a simple function that will distribute the squares on your web page with equal margins (top, left, right, bottom). I took it from 1.
The dlt function calculates the number of columns and defines the rotation amount for each column (in my example the maximum rotation value is 40). The rest of the code are purely some math checks in order to make it work correctly.
In order to get a better result, you should play with the size of each square, but be careful because the dispatch function also needs to know the size of the square to calculate how many squares will be allowed to be displayed per row. I'll let you have fun with it ;)
​

Related

apply a function over 2 consecutive images in an imageCollection in google earth engine

the function .map applies a function to every individual image in an ImageCollection. And the function .iterate applies a function to one image and the output of the calculation done to the precedent image on an ImageCollection.
The first only works with one image each time, and the second implies modifying each image and utilize it to any calculation with the next one.
I need a function that works like .iterate, but does not modify the precedent image. I just need to do:
image (time -1) / image (time 0).
I can not find a way to do it,
thanks for your help
i have tried,
var first = ee.List([
ee.Image(1).set('system:time_start', time0).select([0], ['pc1'])
]);
var changeDET = function(image, list) {
var previous = ee.Image(ee.List(list).get(-1));
var change = previous.divide(image.select('pc1'))
.set('system:time_start', image.get('system:time_start'));
return ee.List(list).add(change);
};
var cumulative = ee.ImageCollection(ee.List(imageCollection.iterate(changeDET, first)))
.sort('system:time_start', false)
What you can do is to convert your imageCollection into a ee.List object, then map over that list with an index variable to access the previous image. Example code is below:
var length = yourImageCollection.size();
var list = yourImageCollection.toList(length);
var calculated_list = list.map(function(img) {
var index = list.indexOf(img)
img = ee.Image(img);
var previousIndex = ee.Algorithms.If(index.eq(0), index, index.subtract(1));
var previousImage = ee.Image(list.get(previousIndex)):
var change = ee.Image(previousImage.divide(img)
.copyProperties(img, ["system:time_start"]));
return change;
})
I'm not sure what you want to do with the first image, so when map function reach the first image, previousIndex will equal to index. In other words, the first image will be divided by itself (as there is no image before it).
Hope this helps.

easy way of ensuring one element is always in front of everything else?

on a website I want to have an element take up the entire space of the screen (after an event), but I can't seem to manage to get it in front of all the other elements on my website. Do I have to set positions and z-indexes for everything or is there another way of setting the element I want in front of everything else?
Brute force.
function getMaxZ() {
var all = document.querySelectorAll('*');
var len = all.length;
var maxZ = 0;
var dv = document.defaultView;
for (var i = 0; i < len ; i++) {
var el = all[i];
var thisZ = el.currentStyle ? el.currentStyle : dv.getComputedStyle(el, null);
thisZ = thisZ.zIndex.replace(/[^\d]/,'') * 1;
if (thisZ > maxZ) maxZ = thisZ;
}
return maxZ;
}
alert(getMaxZ());
If you want this thing always on top, just set its z-index to 999 (or something higher than you know everything else is).

ThreeJS: 3D Object Area Calculation (Triangulated)

I need to calculate the area/surface of a whole object in threeJS. Thats what I have:
var _len = object.geometry.faces.length,
_area = 0.0;
if (!_len) return 0.0;
for (var i = 0; i < _len; i++) {
var va = object.geometry.vertices[object.geometry.faces[i].a];
var vb = object.geometry.vertices[object.geometry.faces[i].b];
var vc = object.geometry.vertices[object.geometry.faces[i].c];
var ab = vb.clone().sub(va);
var ac = vc.clone().sub(va);
var cross = new THREE.Vector3();
cross.crossVectors( ab, ac );
_area += cross.lengthSq() / 2;
}
The results are kind of wrong. I get a floating value, fine, but comparing a very small object with a big object. The smaller could have a bigger surface with the provided code. I checked on many different objects and got not realistic values, when comparing them.
Actually the objects having the biggest faces, but being the smallest in the overall surface, seem to have to highest values with the current version of the code.
I hope someone could have a look at the code and see whats wrong. Very much appreciated!
You are using lengthSq(), is that right? I guess you need the length of the cross vector, not the length squared.

How does one determine the height of a data point using the ASP.Net charting controls?

I have a stacked column chart like so:
I'm using a text annotation to display the $2495 in the rightmost stacked column. I've determined the proper y position experimentally - obviously that won't work for dynamically generated content.
Does anyone know how I can determine the height of the data points which compose the column? I presumed it would be something like:
Chart1.Series[0][0].Height + Chart1.Series[1][0].Height + Chart1.Series[3][0].Height + Chart1.Series[4][0].Height
But, alas, it is apparently not that simple. Any thoughts or insight would be greatly appreciate.
Check out this link
http://support2.dundas.com/OnlineDocumentation/WebChart2005/Custom_Drawing_Using_the_Paint_Event.html
See the examples at the bottom.
It turns out that it's all much simpler than I thought...the annotations use chart coordinates. This means that all you have to do is sum the actual values and use that as a y coordinate. I ended up doing this to calculate the heights of the respective series:
private int CalculateHeight(int i, ChartGraphics graphics)
{
var height = 0.0;
// find the respective heights of series i, add them together
for (var x = 0; x < this.Chart1.Series.Count(); x++)
{
height += this.Chart1.Series[x].Points[i].YValues[0];
}
return (int)height;
}
I then call that function like so:
for (var i = 0; i < chart.Series[0].Points.Count(); i++ )
{
var height = this.CalculateHeight(i, e.ChartGraphics);
this.Chart1.Annotations[i].Y = height + verticalPadding;
}
Much simpler than I thought.

When to render Legend in Flex

My Flex chart has code that creates a legend from each data series. Currently, I have the drawLegend function execute when a button is clicked.
I am trying to get the legend to draw automatically but I am having trouble determining when to call the drawLegend function. Users click on an 'Update' button which retrieves data. I want the legend to get created after this, without the users having to click on another button.
I have put my drawLegend function in several places (ResultHandler, afterEffectEnd(for chart animation, etc.) and nothing works.
Sometime after the series has been added to the chart and after the series animation ends, the legend can be added.
How can I trap this point in time and call my function?
Any ideas?
Below is the code I used to create the legend. Note that even though the code processes each series, I noticed that the Fill color is null if it is called too early.
private function drawLegend(event:Event):void {
clearLegend();
// Use a counter for the series.
var z:int = 0;
var numRows:int;
if (chart.series.length % rowSize == 0) {
// The number of series is exactly divisible by the rowSize.
numRows = Math.floor(chart.series.length / rowSize);
} else {
// One extra row is needed if there is a remainder.
numRows = Math.floor(chart.series.length / rowSize) + 1;
}
for (var j:int = 0; j < numRows; j++) {
var gr:GridRow = new GridRow();
myGrid.addChild(gr);
for (var k:int = 0; k < rowSize; k++) {
// As long as the series counter is less than the number of series...
//skip columnset group
if (chart.series[z] is LineSeries || chart.series[z] is ColumnSeries){
if (z < chart.series.length) {
var gi:GridItem = new GridItem();
gr.addChild(gi);
var li:LegendItem = new LegendItem();
// Apply the current series' displayName to the LegendItem's label.
li.label = chart.series[z].displayName;
// Get the current series' fill.
var sc:SolidColor = new SolidColor();
sc.color = chart.series[z].items[0].fill.color;
// Apply the current series' fill to the corresponding LegendItem.
li.setStyle("fill", sc.color);//was just sc
// Apply other styles to make the LegendItems look uniform.
li.setStyle("textIndent", 5);
li.setStyle("labelPlacement", "left");
li.setStyle("fontSize", 9);
gi.setStyle("backgroundAlpha", "1");
gi.setStyle("backgroundColor", sc.color);
//gi.width = 80;
// Add the LegendItem to the GridItem.
gi.addChild(li);
}
}
// Increment any time a LegendItem is added.
z++;
}
}
}
Well, I couldn't quite figure out what event to trap so I used the following in the chart's parent container:
chart.addEventListener(ChartItemEvent.ITEM_ROLL_OVER,drawLegend);
Seems to work ok.

Resources