HTML table scale to fit - html

I have a KPI dashboard with a lot of small charts. One type of chart is in fact a HTML table. It is displayed in a DIV.
<div style="width:400px; height:250px;overflow:hidden">
<table>
<tr><th>Col1</th><th>Col2</th></tr>
<tr><td>Row1</td><td>Row2</td></tr>
</table>
<div>
Currently, I hide the overflow. I would like to make the table 'fit' the div.
How can I make this table to fit/scale down to the DIV if it would become too big to diplay? Ideally, the text would also shrink.

This CSS will make your table have the same height/width as the container you are using. Borders/background are only added for visualising what happens.
Shrinking the text will however be far more challenging. There is probably no way without using javascript to achieve that. And even if you did, content might end up being unreadable because of a too small font-size.
I managed to come up with some javascript/jquery code to change the font-size until the table fits the div or the font-size reaches 5px (= unreadable). Of coarse you will need to edit some of it yourself (because it would apply on all tables if you don't change the selectors to id's)
[JSFiddle]
table{
width: 100%;
background-color: red;
}
th, td{
width: 50%;
border: blue solid 1px;
}
Jquery / Javascript
$(document).ready(function () {
var HeightDiv = $("div").height();
var HeightTable = $("table").height();
if (HeightTable > HeightDiv) {
var FontSizeTable = parseInt($("table").css("font-size"), 10);
while (HeightTable > HeightDiv && FontSizeTable > 5) {
FontSizeTable--;
$("table").css("font-size", FontSizeTable);
HeightTable = $("table").height();
}
}
});

Here is what I use currently, it is embedded in a project (see for example the classes), but feel free to use it as inspiration.
scaleTable = function (markupId) {
//This hacky stuff is used because the table is invisible in IE.
function realWidth(obj){
var clone = obj.clone();
clone.css("visibility","hidden");
$('body').append(clone);
var width = clone.outerWidth();
clone.remove();
return width;
}
function realHeight(obj){
var clone = obj.clone();
clone.css("visibility","hidden");
$('body').append(clone);
var height = clone.outerHeight();
clone.remove();
return height;
}
var table = $("#"+markupId+" table:first-of-type");
var tablecontainer = $("#"+markupId).parents( ".scalabletablecontainer" );
var scalex = tablecontainer.innerWidth() / realWidth(table);
var scaley = tablecontainer.innerHeight() / realHeight(table);
var scale = Math.min(scalex, scaley);
if (scale<1.0) {
var fontsize = 12.0 * scale;
var padding = 5.0 * scale;
$("#"+markupId+" table tbody").css("font-size", fontsize + "px");
$("#"+markupId+" table tbody TD").css("padding",padding + "px");
$("#"+markupId+" table TH").css("padding",padding + "px");
}
};

Get table and div dimensions as shown in the previous comments. Then apply css
transfrom:scale(factorX, factorY)
to the table.

Related

Bootstrap - match vertical column heights that are not in a row

I've a rather complicated website design I'm working on. I have the following 4 containers (I call them that, but they don't have the .container class)
In a wide screen layout:
In a narrow screen layout:
The issue I'm having is matching the total height of the white, grey and yellow containers with the blue container on a wide screen layout:
The grey and yellow containers are in a .row div, so adding the style { display: inline-flex } makes them the same height on a narrow screen layout:
However, this moves them completely to the side in the wide screen layout and this wouldn't match the combined white, grey and yellow containers with the blue container:
I tried a JavaScript solution as #Paulie_D recommended.
$(window).load(function () {
NormalizeHeights();
});
window.onresize = function (event) {
NormalizeHeights();
}
function NormalizeHeights() {
if (window.innerWidth >= 768) {
var carousel = $(".carousel-container");
var dashTop = $(".dash-row-top");
var panelLeft = $(".dash-row-bottom .panel-lightgray");
var panelRight = $(".dash-row-bottom .panel-yellow");
var carouselHeight = parseFloat(carousel.css('height'));
var dashTopHeight = parseFloat(dashTop.css('height'));
var panelLeftHeight = parseFloat(panelLeft.css('height'));
var panelRightHeight = parseFloat(panelRight.css('height'));
var dashBottomHeight;
if (panelLeftHeight > panelRightHeight) {
dashBottomHeight = panelLeftHeight;
}
else {
dashBottomHeight = panelRightHeight;
}
if (carouselHeight > (dashTopHeight + dashBottomHeight)) {
var difference = carouselHeight - (dashTopHeight + dashBottomHeight);
panelLeft.css("height", (dashBottomHeight + difference));
panelRight.css("height", (dashBottomHeight + difference));
}
else {
var difference = (dashTopHeight + dashBottomHeight) - carouselHeight;
carousel.css("height", (carouselHeight + difference));
panelLeft.css("height", (dashBottomHeight));
panelRight.css("height", (dashBottomHeight));
}
}
}
This works, sort off, but it's extremely unlikable in my estimation.
I had a similar problem and the solution I found was rather ugly but worked for me.
I used divs that would clear formats BUT would their presence would be conditioned (using ng-if). Programmatically, I measured the width of the screen and set a threshold. If the width was above the threshold, I set the location of the divs, measured the height of the contents and, when applicable, forcefully changed the height of all the relevant divs to look the same (note that you would need to set this size update AFTER A TIMER is fired to let the rendering to complete).
Hope this gives you some ideas and remember: I was the first to call this ugly.

Reduce the size of text in angularjs when line breaks?

I have a responsive app for desktop and mobile.
In the app i have a div which randomly shows texts of all kinds of lengths.
I want to do the following:
If the line breaks because the length of the text is too wide for the width of that div, i want the font-size to reduce itself (I am using em's in my app).
Is it something i need to build directive for it? is it something that was built and used wildly?
Writing a robust solution for this problem is going to be non-trivial. As far as I know, there's no way to tell whether a line of text breaks. However, we do know the criteria for line breaking is the width of the text being wider than the element, accounting for padding.
The Canvas API has a method called measureText which can be used to measure a string, using a given context with a font and size set. If you spoof the settings of the element with a canvas, then you can measure the text with the canvas and adjust the size until it fits without overflowing.
I've written up a rough implementation of the way I would tackle this.
function TextScaler(element) {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
var scaler = {};
scaler.copyProps = function() {
var style = element.style.fontStyle,
family = element.style.fontFamily,
size = element.style.fontSize,
weight = element.style.fontWeight,
variant = element.style.fontVariant;
context.font = [style, variant, weight, size, family].join(' ');
};
scaler.measure = function(text) {
text = text || element.innerText;
return context.measureText(text);
};
scaler.overflows = function() {
var style = window.getComputedStyle(element),
paddingLeft = style['padding-left'],
paddingRight = style['padding-right'],
width = style.width - paddingLeft - paddingRight;
return scaler.measure() > width;
};
scaler.decrease = function() {
// decrease font size by however much
};
scaler.auto = function(retries) {
retries = retries || 10;
if(retries <= 0) {
scaler.apply();
console.log('used all retries');
}
if(scaler.overflows()) {
scaler.decrease();
scaler.auto(retries - 1);
} else {
console.log('text fits');
scaler.apply();
}
};
scaler.apply = function() {
// copy the properties from the context
// back to the element
};
return scaler;
}
After you've sorted out some of the blank details there, you'd be able to use the function something like this:
var element = document.getElementById('');
var scaler = TextScaler(element);
scaler.auto();
If it doesn't manage to decrease it within 10 retries, it will stop there. You could also do this manually.
while(scaler.overflows()) {
scaler.decrease();
}
scaler.apply();
You'd probably want some fairly fine tuned logic for handling the decrease function. It might be easiest to convert the ems to pixels, then work purely with integers.
This API could quite trivially be wrapped up as a directive, if you want to use this with Angular. I'd probably tackle this with two attribute directives.
<div text-scale retries="10">Hello world</div>
Of course, if it's not important that all the text is there onscreen, then you can just use the text-overflow: ellipsis CSS property.

CSS - flexible number of columns with width determined by content - possible?

This HTML fragment spreads a long list of short items over a series of columns so that it's easier to scan and doesn't take up as much vertical space. Everything is neatly aligned and the number of columns automatically adjusts itself if you resize the browser window. That's all great. The only problem is that the width of each column is hardcoded in the CSS.
<!doctype html>
<style>
ul.hlist {
width: 80%;
column-width: 6em;
-moz-column-width: 6em;
-webkit-column-width: 6em;
}
ul.hlist > li { display: block; }
</style>
<p>This header unconditionally uses one or more of these deprecated
integer typedefs:</p>
<ul class="hlist">
<li><code>caddr_t</code></li>
<li><code>daddr_t</code></li>
<li><code>fsid_t</code></li>
<li><code>quad_t</code></li>
<li><code>u_int_t</code></li>
<li><code>u_quad_t</code></li>
<li><code>u_int16_t</code></li>
<li><code>u_int32_t</code></li>
<li><code>u_int64_t</code></li>
<li><code>u_int8_t</code></li>
<li><code>u_char</code></li>
<li><code>u_short</code></li>
<li><code>u_int</code></li>
<li><code>u_long</code></li>
<li><code>n_short</code></li>
<li><code>n_long</code></li>
<li><code>n_time</code></li>
</ul>
With some JavaScript, one can scan the list and override column-width to the actual width of the widest list item; there's some fiddliness because each <li> is stretched to the current width of the column, so you have to look inside, but that's not a serious hurdle.
function innerWidth (el) {
var kids = el.children;
var w = 0;
for (var i = 0; i < kids.length; i++)
w += kids[i].offsetWidth;
return w;
}
function setColumnWidth (list) {
var items = list.children;
var mW = 0;
for (var i = 0; i < items.length; i++) {
var w = innerWidth(items[i]);
if (w > mW)
mW = w;
}
list.setAttribute("style",
"column-width:" + mW + "px;" +
"-moz-column-width:" + mW + "px;" +
"-webkit-column-width:" + mW + "px");
}
document.addEventListener("DOMContentLoaded", function (e) {
var lists = document.getElementsByClassName("hlist");
for (var i = 0; i < lists.length; i++)
setColumnWidth(lists[i]);
});
The question is, is there any way to get the same (or nearly so) effect as this JS using only CSS? Please note:
In the example, every <li> has its contents wrapped in a <code>, but your answer must not rely on this, because it ain't necessarily so in other cases.
I already have an entirely client-side solution, and additional server-side processing in context is extremely awkward, so I strongly prefer client-only answers.
Answers involving experimental or not-yet-deployed-at-all CSS features are just fine.
Rendering without JS: http://jsfiddle.net/7F8n6/2/ (columns are rather too wide)
Rendering with JS: http://jsfiddle.net/7F8n6/3/
The items are inside <code> elements so by default are rendered with a monospaced font. That means their width only depends on the number of characters.
Assuming you can influence the complete page on the server, determine the item with the most characters on the server. Here it's 9.
Now generate a CSS rule in the page that sets the column width to 9 characters:
column-width: 9ch;
-moz-column-width: 9ch;
-webkit-column-width: 9ch;
The 'ch' unit is the width of a single '0' (zero). It's not supported on every browser, see MDN, so I don't know if this solution is good enough for you.

Autosize HTML table cell height based on content when rowspan is involved

Is there a way to autosize HTML table height based on content? Also if it's a cell (or cells) next to a neighbor cell with multiple rowspans.
E.g. if I have a table like this (cell on the right has Rowspan="2" and height of the cell content = 600px, in each cell on the left height of the cell content = 150px):
there is a gap between 2 cell consents on the left because cells themselves autosized their height. I'd like it to look like this:
Where top cells automatically collapse to cell content height. Is there anyway to achieve this?
This sets the last row of cells to the correct height (demo):
function grow(td) {
var table, target, high, low, mid;
td = $(td);
table = td.closest('table');
target = table.height();
low = td.height();
// find initial high
high = low;
while (table.height() <= target) {
td.height(high *= 2);
}
// binary search!
while (low + 1 < high) {
mid = low + Math.floor((high - low) / 2);
td.height(mid);
if (table.height() > target) {
high = mid;
} else {
low = mid;
}
}
td.height(low);
}
$('tr:last-child td').each(function() { grow(this); });
​
It should be trivial to convert this into plain JavaScript.
Update: For more complicated tables, you'll want to replace the last line with this (demo):
$.each($('td').get().reverse(), function() { grow(this); });
​
The idea is to call grow() on every cell, starting with the last row and working upwards.
considering table id="mytable" it would be:
$("#mytable").find("td").each(function(){
var ContentHeight = $($(this).html()).height();
$(this).height(ContentHeight);
});
at the end of the your page create a javascript code and let it do it for you:
<script type="text/javascript">
document.getElementById("idOfTd").style.height="100px";
</script>
I think it better create like this http://jsfiddle.net/miqdad/w9QYB/

Is there any way to set a CSS min-width on an element that is floated?

I have this html:
<div id="subNav"></div>
<div id="feed"></div>
<div id="feedBar"></div>
I have floated all of these divs left. I set the width of #subNav and #feedBar, but on #feed I set its min-width . It takes the min-width even though the window is larger. Is there any way that with floating you can make the min-width work? I am trying to make a flexible layout on the page.
The following answer uses a JavaScript solution, in response to #Chromedude's comment (to the original question):
#David Is there any way to override this behavior? with javascript?
I'm sure there's a far more simple way of doing this (certainly with a JavaScript library), but this was the best I could come up with at this time of morning (in the UK):
var feed = document.getElementById('feed');
var width = document.width;
var feedBarWidth = document.getElementById('feedBar').clientWidth;
var subNavWidth = document.getElementById('subNav').clientWidth;
feed.setAttribute('style', 'width: ' + (width - (subNavWidth + feedBarWidth)) + 'px');
JS Fiddle demo.
Using jQuery (just as a suggestion as to the ease offered by a library):
var bodyWidth = $(document).width();
var subNavWidth = $('#subNav').width();
var feedBarWidth = $('#feedBar').width();
$('#feed').css('width', bodyWidth - (subNavWidth + feedBarWidth));
Use a grid system such as the one in Foundation 3. When placed on a div representing an element of the grid, min-width behaves just fine.
To get min-width to work without a grid, use a CSS rule that inserts an invisible pseudo-element with the desired minimum paragraph width.
p:before {
content: "";
width: 10em;
display: block;
overflow: hidden;
}
Further details are at the source where I learned this.