Implementing weighted flexible layout with CSS - javascript

Please take a look at this jsFiddle and press the only button to fill the list up. As you can see DIV elements inside the list are resized to fill the parent contained. This code does exactly what I want to do, but I think the way I implement this is too complex for such a seemingly simple task. Here is the code for the algorithm to assign height to inner elements:
fill = function() {
//Loop through all elements once to get total weight
var totalWeight = 0;
var totalHeight = $("#container").height() - 15; //need a little extra empty space at the buttom
$(".list").each(function(i) {
totalWeight += parseInt($(this).attr('weight'));
totalHeight -= parseInt($(this).css('margin'));
});
//Loop though the element a second time to set the relative height
$(".list").each(function(i) {
var element = $(this);
element.css("height", (element.attr("weight") / totalWeight) * totalHeight);
});
}
My question is, is the best we can do? Are there any other - hopefully faster or more elegant -- ways to achieve this functionality with reasonable cross-browser compatibility? I need to support newer Firefox, Chrome, and Safari only. I was reading about flex-box here and looking at its promising specs, but it does not look like flex-box can do weighted flexible layout consistently across browsers. If I am wrong, please show me a simple example of how this could be achieved.
This type of weighted flexible linear layout is not uncommon, for example it is available in Android SDK as one of the layout options. What is the recommended way to resize elements to fill their parent container, relative to a weight value assigned to them? A pure CSS solution would be wonderful, if at all possible.

Just a quick look over it, after about 30 mins googling. I may do a demo but don't really hav much time.
Have you looked here
html5rocks
coding.smashmag...
tutsplus
umarr
w3c
benfrain
There are some good examples on the 6th one
edit:
I was looking thought the firefox developer section on their website and found
developer.mozilla...
I also found another example with a download!!
github..
this might give you some direction for firefox and the rest should be in the other links I have provided

Related

Can I use javascript to place one element on different places, one for mobile and one for desktop?

I am adding an element in the dom using javascript. I have added an using insertBefore() to place it where I want it on the mobile view. But in desktop it is supposed to be placed on a different space on the website. How can i solve this?
Just using CSS is not an option due to already existing elements that i cant't move.
var priceWrapper = document.querySelector('.price-info-wrap')
var mainContainer = document.querySelector('.price-info')
var addUrgency = document.getElementById('urgency')
priceWrapper.insertBefore(addUrgency, mainContainer)
The code provided is how I have placed "addUrgency" witch is the div I need to put elsewhere on desktop.
You can do it, but it's a bad idea.
Lay out your elements starting with smallest screen width you need, then work outwards from there using CSS Media queries to adjust the layout at specific screen widths as and when you need to.
In this case, if you can't do it any other way you could have both elements where you like them and then show/hide depending on the viewport width. Something like:
#media (min-width:800px) {
//your non-mobile styles and classes go here
.desktop-element{
display: inline-block;
}
.mobile-element{
display:none;
}
}
You could use navigator.userAgent and determine if the browser is a mobile browser. There is also an question with really good answeres on doing that on StackOverflow: Detecting a mobile browser
Another option is to check the viewport-size with javascript. Which can be a better solution in the case you have css-rules in place that are responsive to the viewport-size , like: #media (width):
let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
After that it is a simple if-else to decide where to place your element.
You can use the onresize event. But, I have to note, that having two identical elements (perhaps using clone() to copy #addUrgency) in the DOM on their right places and display/not display them using CSS media queries instead of using Javascript to re-lay elements every time the viewport is resized is a better solution. However, to answer your question here is the most straightforward approach using your code. It also worth to note, that resize event can fire pretty fast, so you probably will want to throttle the function relay (answers are on StackOverflow).
function relay(){
var addUrgency = document.getElementById('urgency');
if(`mobile view`){ //here goes a condition to determine what view you have.
var priceWrapper = document.querySelector('.price-info-wrap');
var mainContainer = document.querySelector('.price-info');
priceWrapper.insertBefore(addUrgency, mainContainer);
}else{
// Insert where you want it on desktop view
}
}
window.onload = function() {
relay();
document.body.addEventListener("resize", relay);
};
You could do this using JavaScript but I wouldn't recommend this approach as I believe this is achievable in most cases with plain HTML and CSS. One method would be using display: grid and placing the elements in the desired rows/columns on mobile (If you are of course utilizing a mobile-first approach) and then redistributing them on larger screens with media queries. Additionally, you could of course make use of position: absolute whenever this strategy does not completely do the job.
Here is a great article, in case you are not completely familiar with display: grid.

JS grid performance comparison

I was using angular-ui-grid (http://ui-grid.info/) to display tabular data. On the whole, it was quite slow and so we decided to use ag-grid (https://www.ag-grid.com/). This was much more performant and better to deal with for regular-sized data-sets.
However, now we are working with some tabular data of the size of 100 cols x 10,000 rows (~1M cells) and the grid seems quite slow in performance.
I was wondering if anyone had used hypergrid (https://fin-hypergrid.github.io/core/2.0.2/) -- it seems to 'solve' the issue of large cols x large rows and in their demo it seems much faster (almost by an order of magnitude) on large data sets.
How does hypergrid compare to ag-grid or react-virtualized in performance on large data sizes?
I haven't tried any of those example libraries you mentioned, but perhaps I could explain why fin-hypergrid stands out the most. My opinion is primarily based on my JavaScript knowledge and how this kind of stuff works in the back.
I should probably start with react-virtualized and ag-grid:
Both use the way of populating the DOM and only displaying a portion of data to the view, dynamically removing things from the DOM that aren't visible anymore and adding the upcoming things in advance. Now the problem here lies in adding and removing things in the DOM since this tends to be executed really fast / multiple times a second. Because of this we experience some lag or jitter. You can actually check Web Console > Profiles > Record JavaScript CPU Profiles and see that this method takes time to complete. So the only thing that differs from react-virtualized and ag-grid are their algorithms of applying these changes in the smoothest possible manner.
ag-grid, from what I can see, is the one that suffers the most from this issue as you could actually see some elements that haven't finished rendering yet and experience severe lag when you scroll too fast.
react-virtualized on the other hand does a splendid job implementing its algorithm in the smoothest possible manner. This might be the best library available in the DOM manipulation category though it still suffers from the problem of manipulating the DOM too fast which creates lag, though this is only seen when large chunks of data are involved.
Here are the reasons why fin-hypergrid excels:
The best asset of fin-hypergrid is it doesn't perform DOM manipulation at all so you are already saved from the problem caused by adding and removing things too fast since it uses <canvas>
fin-hypergrid also displays only data that the user sees and dynamically removes things that aren't visible. It also adds in advance to achieve a smooth scroll feeling, so no still-rendering items are shown.
fin-hypergrid also does a really great job on their scrolling algorithm to attain the smoothest possible manner, so there is no jitter or lag.
Now that doesn't mean that hypergrid is all good, it has some disadvantages too:
Since fin-hypergrid is made with HTML5 Canvas, styling it will become a real pain as it doesn't accept CSS. You would need to style it manually.
A few things to keep in mind are form controls such as <select>, radio buttons, checkboxes, etc. would be a real pain to implement. If you are trying to implement something like this then proceed with caution.
It's primarily used for displaying data with simple column edits, not involving anything other than a textbox, and achieving the most smooth scroll feeling.
Now in conclusion, I would probably suggest using react-virtualized instead since it offers the smoothest scroll, above fin-hypergrid. If you are willing to disregard the downsides of fin-hypergrid, then fin-hypergrid is the best option.
UPDATED:
Since we discussed JS / CSS, canvas implementations of these tables. I should have mentioned the last possible contender though this one is not primarily a js table library but a framework in which Google Sheets might have been used it is called d3.js.
d3.js has the speed and power of canvas and at the same time retains HTML structure, this means that it is possible to style it with CSS!
It maximizes the usage of HTML 5 SVG
I can't say anything more better in d3.js
The only downsides of d3.js in this discussion is that:
There is no available good table libraries out there that uses d3.js. Google Sheets that is. But they do not share code.
d3.js is just very hard to learn, though there are lots of stuff out there that helps us learn this faster but not that fast.
If you wanted speed of Canvas with CSS styling capabalities then d3.js is the key the problem is learning it.
I have gone through different data grid options. Then I found this.
Hope this answer helps to anyone who is looking for performance comparison between data grids.
Few points to be noted here, even you have gone through with the article I provided.
1 - Once a grid is 'fast enough', which means the rendering lag is not
noticeable, then it doesn't matter which grid is faster than the next.
2 - A canvas based grid is not a HTML grid - you cannot customise it
with HTML. The grid will struggle to be styled / themed / customised
by the standard JavaScript / CSS developer.
Pick your poison because it is not just the performance when it comes to the consumer level.
Have you considered using something designed for large data sets?
Clusterize.js
I believe the way it works is it only loads the elements data for the ones you are looking at. Therefore the browser doesn't lag because it has the elements need to display the viewport.
The demo page loads 3 examples with 500,000 elements each (1,500,000 total elements).
Update - With Example Snippet
Because I do not have 100,000 x 200 elements of data to load I build 100 x 200 using JavaScript.
Then I copy that array and insert it into the data array 1000 times.
This way I can reach your total data set size without overloading the JavaScript engine.
Since it is hard to tell that it is really doing 100,000 rows I called the getRowsAmount() function which is displayed at the top of the output.
You may need to play with the block & cluster sizes based on your viewport but this should show you that this library is totally possible of supporting your needs.
$(function() {
var dataBlock = []
var data = [];
const rows = 100000
const cols = 200;
const blockSize = 100;
const blocks = rows / blockSize;
for (let i = 0; i < cols; i++) {
$("thead tr").append(`<th>C${i}</td>`);
}
for (let j = 0; j < blockSize ; j++) {
var tr = $("<tr />");
for (var i = 0; i < cols; i++) {
tr.append(`<td>R${j}-C${i}</td>`);
}
dataBlock.push($("<div />").append(tr).html());
}
for (let i = 0; i < blocks; i++) {
$.merge(data, dataBlock);
}
var clusterize = new Clusterize({
rows: data,
scrollId: 'scrollArea',
contentId: 'contentArea',
rows_in_block: 10,
blocks_in_cluster: 2,
});
$("#totalRows").text(clusterize.getRowsAmount());
});
table td {
white-space: nowrap;
padding: 0 5px;
}
<html>
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://clusterize.js.org/css/clusterize.css" rel="stylesheet" />
<script src="https://clusterize.js.org/js/clusterize.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
Total Rows: <span id="totalRows"></span>
<div class="clusterize">
<div id="scrollArea" class="clusterize-scroll">
<table class="table">
<thead>
<tr></tr>
</thead>
<tbody id="contentArea" class="clusterize-content">
<tr class="clusterize-no-data">
<td>Loading data…</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
The library supports appending data so with your large data sets your may want to load some of your data through AJAX.
I used free version of handsontable for big datasets.
See example with 10000*100 cells - http://jsfiddle.net/handsoncode/Lp4qn55v/
For example, for angular 1.5:
<hot-table class="hot handsontable htRowHeaders htColumnHeaders" settings="settings"
row-headers="rowHeaders" datarows="dba">
<hot-column ng-repeat="column in Value" data="{{column.COL1}}" >
</hot-column>
</hot-table>
See documentation here

Equal height rows of articles on responsive design [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am trying to use https://github.com/Sam152/Javascript-Equal-Height-Responsive-Rows java script plugin to achieve equal row heights on my article rows of responsive grid on http://www.snapchamp.com. The plug-in is rendering some pages ok but in some cases it's messing the margins between element like below:
Plugin fails when I zoom the browser window and also when I turn the orientation of ipad or mobile devices. In mobile even with single element grid the margin go messy.
So my question are:
1) Is there a better js plug-in that achieves better results?like http://brm.io/jquery-match-height/ or something else that you used in past.
2) What is order of page css rendering and javascript execution? What can be reason for such grid margin issues?
3) I tried searching for zoom events on browser and answers were almost 3-5 years old. Wonder if we have any new event that notifies javascript of zoom event on browser.
I put together this simple bit of js/jQuery for you to perhaps use as a solution.
The fiddle.
jQuery(document).ready(function(){
//Find max height:
var maxH = 0;
var containers = jQuery("div.container");
var i = 0;
containers.each(function() {
var h = jQuery(this).height();
if(h > maxH)
maxH = h;
i += 1;
if(i == containers.length)
updateContainerHeight();
});
function updateContainerHeight()
{
if(typeof maxH == 'undefined' || typeof maxH == 'null')
return;
containers.css({'height': maxH + 'px'});
}
});
What it does is iterate through all of the container elements, measure them, and if the current element is higher than the previously highest element, it replaces the maxH variable. Once all containers have been reviewed, a function is fired to change all element heights to the highest.
This shouldn't affect your responsive as it doesn't care about width or how many units are in a row. A more sophisticated solution would only compare those in a single row, and you can check that by seeing how wide the parent element and how wide the containers are, then divide to determine in the current responsive layout how many columns are desired for each row and adjust from there.
I hope this helps give you some direction.
I realized that most solution dealing with javascripts involved changes with heights. If you look at the dom on site, you will realize that under article we had another element named entry. I was trying to make article of equal height but after reviewing code I realized I could even make a child element of same height. I switched from article to entry and my problem resolved to certain extent. Then once in a while re-sizing I was again getting margin squishing problem. After some time realization came that my theme is using masonry plugin and may be that is causing problem/conflict. I removed masonry and site looks better. Still need to test fully on different devices and different scenarios to test if site works.
Want to take this opportunity to Thanks #practically for effort and help provided. His solution provided also will work but will provide highest height to all elements across rows. The plugin ( https://github.com/Sam152/Javascript-Equal-Height-Responsive-Rows) works on rows wise height but is little slow to update the site and cause a bit of flicker.

scrollTop inconsistencies when (zoom < 1)

This is my first SO question, so please forgive any question faux-pas!
I have two containers on my HTML DOM that float:left. Each has content that must be perfectly aligned with the other. The left container (A) has overflow-y:hidden while the right container (B) has overflow-y:scroll. I use an onscroll callback to set the scroll position of container A like such:
A.scrollTop = B.scrollTop;
This works great in 99% of use-cases... until a client zooms below 100%. When zoom is below this level, rows in one container are sometimes 1 pixel off from those in the other. My first guess is that this is a rounding issue, but I can't figure out where I can find values that I could use to build an algorithm to predict when & how the error will occur. In addition, both containers have exactly the same height, and their content is of identical height as well, so I'd expect any rounding errors to be the same for each of them!
I've created a jsFiddle demonstrating the behavior here. (I've used divs in this example, but other elements exhibit the same behavior) (I'm testing in chrome)
Can anyone explain why these two containers exhibit different behaviors when setting scrollTop to the same value? Also, given that browser-zoom detection is difficult at best
(discussion here) does anyone know an efficient way to identify and correct for this issue?
Looks like scaling problem, not sure.
Forcing scrollTop might help.
JSFiddle demo here.
$('#b').on('scroll', function () {
var top = $(this).scrollTop();
if (top != $('#a').scrollTop()) {
$('#a').scrollTop(top);
$(this).scrollTop(top);
}
});
Update: I just revisited this question to see if there were any changes in Chrome's handling of this datapoint... lo and behold, Chrome now returns a floating point value for scrollTop!
Problem solved!

normal flow of html..behaves weird.. Is it right to code positioning in JS?

From a very long time I am thinking of asking this. But was not sure if I should ask this question. I have been very lost seeing the behaviour of html elements with normal flow. It is sometimes very difficult to control them. Specially when I am using server side coding as well to create dynamic content. Sometimes, I take more time to understand what going on with these elements that I take to code server side or javascript. For me its very difficult to understand how a change will affect some other element.
So, I have thought of using absolute and relative positioning for elements and placing them based upon calculation of innerWidth and innerHeight of the window which will also make it responsive. I feel I wil have more control like that.
On window resize I can again position the element to make it dynamic with window resize.
Just like the code below,
window.onload = function()
{
document.getElementById("gamectrl").style.position = "absolute";
document.getElementById("gamectrl").style.top = document.getElementById("rtctrls").offsetTop + 10 + "px";
document.getElementById("gamectrl").style.left = document.getElementById("rtctrls").offsetLeft + 10 + "px";
}
window.onresize = function()
{
document.getElementById("gamectrl").style.top = document.getElementById("rtctrls").offsetTop + 10 + "px";
document.getElementById("gamectrl").style.left = document.getElementById("rtctrls").offsetLeft + 10 + "px";
}
Do you think it is the right way to position html elements? I am very comfortable with this. But I am not sure if this is the right way to do it.
Please share if you have any experience on this. I am very confused about which approach to use. I dont understand the normal flow of html elements properly as I could not find any good resources which discuss them in depth. So, if you know any good resource to learn about normal document flow(in-depth) then do share as well.
I would not use javascript to just reposition an element giving the example you've shown. In your example I would stick to using CSS. If you're concerned about the browser/device resizing then you need to look into using #media queries. If you need to have your elements a certain distance away from the edge of the window or another element you can set the element's margin with percentage values (ex. margin-top: 10%;). Below are some references to positioning with CSS as well as #media queries.
Media Queries: http://css-tricks.com/css-media-queries/ Media
Queries: http://www.w3schools.com/css/css_mediatypes.asp CSS
Positioning: http://alistapart.com/article/css-positioning-101 CSS
Positioning: http://www.w3schools.com/css/css_positioning.asp

Categories