how to make a div match a dynamically created google chart height - javascript

I have a page that dynamically loads a google timeline chart onto a div. The timeline increases in height as you add items on to it. If the chart is smaller than the div, it will be visible with empty space at the bottom. If the chart is larger, it will show scrollbars on the side.
What I would like is for the container div to always show the full chart or, another way, I would like the container div height to dynamically match the height of the chart.
I have tried to approximate the average size of each chart line and then adjust the div height when I load the chart with:
$("#gantt_chart").height(data['num_contents']*46);
But, although that somehow works, it's far from perfect because the approximation on height starts to accumulate with each additional line and the empty space at the bottom of the div increases which is not an elegant solution at all.
How would I ensure that the container div always shows the full chart?
I hope this is clear enough.
Many thanks.

The chart determines its height by either checking the height option passed into the draw call, or by checking the container height if the height option is not specified. I would suggest using the option instead of changing the div height via jQuery. I find the best method for dynamically calculating the chart height is to take the height of a row (typically 41px) times the number of rows, plus some padding for the top and bottom:
var height = data.getNumberOfRows() * 41 + 30;

Though in the doc they have shown to adjust height of div from where we are specifying the id of timeline but I recommend you to have set the height from the internal method.
// set the height for padding(padding height)
var pH = 40;
// get total height of rows (row height)
var rH = dataTable.getNumberOfRows() * 15;
// total chart height (chart height)
var cH = rH + pH;
// Now set this chart height to the timeline via option object
// apart from height, other attributes are just optional
var options = {
height: chartHeight,
colors: ['#339900', '#e6e600', '#B00000'],
tooltip: {
isHtml: true
},
timeline: {
colorByRowLabel: false
},
avoidOverlappingGridLines: true
};

Been trying to do the same thing myself. The top answer wasn’t exactly right and caused an inner scroll bar to appear at times.
Here’s what worked for me:
var barLabelFontSize = 12; //default font size for bar labels
try{barLabelFontSize = options.timeline.barLabelStyle.fontSize; //bar height is dependent on the bar label's font size that you set...
}catch(e){}
var barHeight = barLabelFontSize * 1.196; //found in google api as: this.PU = 1.916 * this.UF.fontSize;
var barMargin = barLabelFontSize * 0.75; //found in google api as: this.Rfa = .75 * this.UF.fontSize;
var rowHeight = barHeight + barMargin * 2; //found in google api as: b.height = 2 * this.Rfa + this.PU (+additional complication for grouped bars, if anyone wants to try work that out it was: b.height = 2 * this.Rfa + this.PU * a.SI.length + this.Qfa * (a.SI.length - 1); (where Qfa is 0.583 * font size, and a.SI.length is the number of grouped bars displayed on the row)
var chartAreaHeight = rowHeight * dataTable.getNumberOfRows();
var axisHeight = 24; //worked out by querying: document.getElementById('timelineChart') getElementsByTagName('svg')[0].getBBox().height;
var whiteSpaceHeight = 28; //trail-and-error to find how much whitespace was required to stop a scroll bar appearing, 27 works too, but I rounded up to play it safe
var chartHeight = chartAreaHeight + axisHeight + whiteSpaceHeight;
You can also reverse engineer this to set the height of the bars using the bar label font size.

Related

How to determine the height and width of HTML user input and tell gridster to fit accordingly?

I'm currently using Gridster.js (http://gridster.net/) in combination with CKEditor.
Once the user saves their content with CKEditor, this content is put into the widget. However the widgets do not automatically resize themselves to fit the content, and while the user is able to resize it themselves, it would be more convienient for the userbase to have it be done for them the moment they press save.
I have tried a few things, but none to any avail. I'm having trouble getting the size of the current content, and then resizing the gridster respectively.
In my code, I have two values to work with. the gridster element (widget), and the value that will be put into it (contents). I have to determine the height of the contents. Once this is done successfully, I will be able to determine if my code for getting the x and y values work.
My current code looks like this:
// Initialization of the gridster element.
// The base dimensions are relevant to understand how we
// calculate the multipliers, later on.
gridster = $(".gridster > ul").gridster({
widget_margins: [10, 10],
widget_base_dimensions: [100, 50],
draggable: {
handle: 'header'
},
resize: {
enabled: true,
max_size: [20, 10],
min_size: [2, 1]
}
}).data('gridster');
And (the relevant bits of) my JavaScript class that handles saving and resizing:
// Saves the content from CKEditor to the gridster widget
this.save = function (data) {
var lastContents = this.default_html + data + '</div>';
$(this.editor).removeClass('gs-w-new');
this.resize_widget(this.editor, lastContents);
$(this.editor).html(lastContents);
this.modal.modal('hide');
};
/* #TODO: resize_widget function */
// if the new content from ckeditor is larger than the
// original size of the widget, we need to make it larger.
this.resize_widget = function(widgetId, contents) {
var element = $('<div>')
.addClass('fake-div-gs-w-resize')
/*
.fake-div-gs-w-resize {
position: absolute;
display: none;
height: auto;
width: auto;
white-space: nowrap;
}
*/
.css('display', 'block')
.html(contents);
var widget = $(widgetId);
var elementWidth = $(element).width(), // I am expecting this to return the width of the content, but it returns 0.
elementHeight = $(element).height(), // As you might imagine, this also returns 0.
width = widget.width(),
height = widget.height();
$(element).css('display', 'none');
console.log(widgetId, widget, width, height, elementWidth, elementHeight);
// this code never gets past here, because element{Height,Width} returns 0.
if (elementHeight > height || elementWidth > width) {
var width_multiplier = 100, // data-x = 1 === width_multiplier px
height_multiplier = 50; // from "widget_base_dimensions: [100, 50],"
var x = Math.round(width / width_multiplier),
y = Math.round(height / height_multiplier),
eX = Math.ceil(elementWidth / width_multiplier),
eY = Math.ceil(elementHeight / height_multiplier);
console.log("setting to x:" + eX + ", y:" + eY + " with width:" + width + ", height:" + height);
if (eX >= x && eY >= y)
gridster.resize_widget(widget, eX, eY);
}
};
Whilst I am not completely confident in my logic for determining the sizes; the main focus of this question is with determining the size of the HTML contents, as what I gathered from other SO posts did not seem to help in my case.
You need to actually add the element to the DOM for the width() and height() functions to work. In your example, the element is not added to the document.
See this JS Fiddle as an example https://jsfiddle.net/y1yf1zzp/10/
I had the same challenge, i.e. dynamic content appearing inside the new tile caused an overflow and appeared outside the tile boundaries. We used the '.scrollHeight' of the tile contents in combination with Zartus' code:
var contentHeight = $widgit.firstChild.scrollHeight;
var tileHeight = $widgit.firstChild.clientHeight;

Is there any way to center text with jsPDF?

I'm trying to create a simple pdf doc using javascript. I found jsPDF but I don't figure out how to center text. Is it possible?
Yes it's possible. You could write a jsPDF plugin method to use.
One quick example is this:
(function(API){
API.myText = function(txt, options, x, y) {
options = options ||{};
/* Use the options align property to specify desired text alignment
* Param x will be ignored if desired text alignment is 'center'.
* Usage of options can easily extend the function to apply different text
* styles and sizes
*/
if( options.align == "center" ){
// Get current font size
var fontSize = this.internal.getFontSize();
// Get page width
var pageWidth = this.internal.pageSize.width;
// Get the actual text's width
/* You multiply the unit width of your string by your font size and divide
* by the internal scale factor. The division is necessary
* for the case where you use units other than 'pt' in the constructor
* of jsPDF.
*/
txtWidth = this.getStringUnitWidth(txt)*fontSize/this.internal.scaleFactor;
// Calculate text's x coordinate
x = ( pageWidth - txtWidth ) / 2;
}
// Draw text at x,y
this.text(txt,x,y);
}
})(jsPDF.API);
And you use it like this
var doc = new jsPDF('p','in');
doc.text("Left aligned text",0.5,0.5);
doc.myText("Centered text",{align: "center"},0,1);
This works in the scratchpad on the jsPdf homepage:
var centeredText = function(text, y) {
var textWidth = doc.getStringUnitWidth(text) * doc.internal.getFontSize() / doc.internal.scaleFactor;
var textOffset = (doc.internal.pageSize.width - textWidth) / 2;
doc.text(textOffset, y, text);
}
I have found that the current version of jsPdf supports a parameter 'align' with the function signature like this:
API.text = function (text, x, y, flags, angle, align)
So the following should give you a center-aligned text:
doc.text('The text', doc.internal.pageSize.width, 50, null, null, 'center');
However, at the current point in time, an error is thrown in the library when strict mode is on because a 'var' is missing.
There is an issue and pull request for it, but the fix hasn't made it in:
https://github.com/MrRio/jsPDF/issues/575
Whoever is looking for this, one day, you might be able to use this to make it easier to center text.
WootWoot, just in case you need more layout options, you could also take a look at my pdfmake library
It supports:
text alignments, lists, margins
styling (with style inheritance)
tables with auto/fixed/star sized columns, auto-repeated headers, col/row spans
page headers and footers
font embedding, and a couple of other options
It works on client-side (pure JS) or server-side (an npm module)
Take a look at the playground to see what's possible
Good luck
I had the same problem and a lot of others while creating PDF-Files (e.g. auto-pagebreak, total-pageCount). So i started writing a little lib, which depends on jsPDF but gives you a lot of features in a way you know them (form HTML/CSS and jQuery). You can find it on GitHub. I hope it makes PDF-Creating easier... =)
Based on #Tsilis answer I have snippet out a plugin here https://gist.github.com/Purush0th/7fe8665bbb04482a0d80 which can align the text left, right and center in the given text container width.
(function (api, $) {
'use strict';
api.writeText = function (x, y, text, options) {
options = options || {};
var defaults = {
align: 'left',
width: this.internal.pageSize.width
}
var settings = $.extend({}, defaults, options);
// Get current font size
var fontSize = this.internal.getFontSize();
// Get the actual text's width
/* You multiply the unit width of your string by your font size and divide
* by the internal scale factor. The division is necessary
* for the case where you use units other than 'pt' in the constructor
* of jsPDF.
*/
var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
if (settings.align === 'center')
x += (settings.width - txtWidth) / 2;
else if (settings.align === 'right')
x += (settings.width - txtWidth);
//default is 'left' alignment
this.text(text, x, y);
}
})(jsPDF.API, jQuery);
Usage
var doc = new jsPDF('p', 'pt', 'a4');
//Alignment based on page width
doc.writeText(0, 40 ,'align - center ', { align: 'center' });
doc.writeText(0, 80 ,'align - right ', { align: 'right' });
//Alignment based on text container width
doc.writeText(0, 120 ,'align - center : inside container',{align:'center',width:100});
maybe... just for easy way, you can read this jsPdf text api doc
doc.text(text, x, y, optionsopt, transform)
where optionspot is an option objet, so, you can do this
{align:"center"}
i.e:
doc.text("Hello Sun", doc.internal.pageSize.getWidth()/2, 10, { align: "center" })
where: doc.internal.pageSize.getWidth() is the page width for pdf sheet
doc.text(text,left,top,'center') can be used to center text. It can be used with array of lines as well but when it is used with array the center does not work right so I have used it in a loop for every object in the array.
var lMargin=15; //left margin in mm
var rMargin=15; //right margin in mm
var pdfInMM=210; // width of A4 in mm
var pageCenter=pdfInMM/2;
var doc = new jsPDF("p","mm","a4");
var paragraph="Apple's iPhone 7 is officially upon us. After a week of pre-orders, the latest in the iPhone lineup officially launches today.\n\nEager Apple fans will be lining up out the door at Apple and carrier stores around the country to grab up the iPhone 7 and iPhone 7 Plus, while Android owners look on bemusedly.\n\nDuring the Apple Event last week, the tech giant revealed a number of big, positive changes coming to the iPhone 7. It's thinner. The camera is better. And, perhaps best of all, the iPhone 7 is finally water resistant.\n\nStill, while there may be plenty to like about the new iPhone, there's plenty more that's left us disappointed. Enough, at least, to make smartphone shoppers consider waiting until 2017, when Apple is reportedly going to let loose on all cylinders with an all-glass chassis design.";
var lines =doc.splitTextToSize(paragraph, (pdfInMM-lMargin-rMargin));
var dim = doc.getTextDimensions('Text');
var lineHeight = dim.h
for(var i=0;i<lines.length;i++){
lineTop = (lineHeight/2)*i
doc.text(lines[i],pageCenter,20+lineTop,'center'); //see this line
}
doc.save('Generated.pdf');
Do this:
First get the page width, get half the page width and use it as the x value, use y value of your choice and pass center as the third param to center your text.
Read more from documentation
let doc = new jsPDF();
let pageWidth = doc.internal.pageSize.getWidth();
doc.text("My centered text",pageWidth / 2, 20, 'center');
This will work fine.
let pdf = new jspdf('p', 'mm', 'a4');
pdf.text("Text to display", pdf.internal.pageSize.getWidth() / 2, 50, null, 'center');
50 is the height i.e. y-axis.
This worked for me:
doc.styles.tableBodyEven = {
alignment: 'center'
}
doc.styles.tableBodyOdd = {
alignment: 'center',
color: '#555555',
fillColor: '#dedede'
}

Determining the Width and Height of an element: True and normal

I would like to know what the best method is to calculate the width and height of an element with Jquery/Javascript (or any other method that might be more accurate). Currently, I am using this Jquery method:
Jquery: See my example: http://jsfiddle.net/AwkF5/1/
var w = $("#wrapper"); //The element dimensions to calculate
$("#displayW").text( "outerWidth:" + w.outerWidth()+ " , outerWidth(true):" + w.outerWidth(true) ); // Displaying the width in the #displayW div
$("#displayH").text( "outerHeight:" + w.outerHeight()+ " , outerHeight(true):" + w.outerHeight(true) ); // Displaying the height in the #displayH div
Now is this the most accurate way to calculate the width/height(including content, padding and border) and TRUE width/height ((including content, padding, border and margin) of an element?
What would be the plain javascript method?
I'm asking because I want to make a background image for the div and I want to know what size it should be...Note that the width and height varies between different browsers...obviously
Thank You
​
This should work for you:
var realWidth = $("#yourBlockId").outerWidth();
realWidth += parseInt($("#yourBlockId").css("margin-left"), 10);
realWidth += parseInt($("#yourBlockId").css("margin-right"), 10);
The same approach for height.

Equal height for divs

I have a site. I want to make 3 vertical divs with equal height. For this purposes I change the height of last block in each column/div.
For example, the naming of 3 columns are:
.leftCenter
.rightCenter
.right
Now I wrote a code which set the equal height for .leftCenter and .rightCenter:
var left = $('.leftCenter').height();
var center = $('.rightCenter').height();
var news = $('#newItemsList').height();
if (center < left)
$('.rightCenter').height(center + (left-center));
else if (center > left)
$('#newItemsList').height(news + (center-left));
news is the latest subblock in left column (there are 3 images in it). So, if central div is bigger than left div, I change the height of news to make them equal. This code works in Firefox, but doesn't work in Chrome. That's the first question. And the last is: how to make equal 3 divs (including right one).
I needed to make elements equal in height and width so I made the following function that allows you to define a height, or width, or really whatever at it. refType would be used if you sent a min-height and needed it to match the height of the tallest element.
elemsEqual = function (options) {
var defaults = {
'type' : 'height',
'refType' : '',
'elements' : [],
'maxLen' : 450
},
settings = $.extend({}, defaults, options),
max = 0;
$(settings.elements.join(",")).each(function () {
max = Math.max( max, parseInt( $(this).css(settings.type) ) );
if(settings.refType.length) max = Math.max( max, parseInt( $(this).css(settings.refType) ) );
});
max = ((max < settings.maxLen) ? max : settings.maxLen);
$(settings.elements.join(",")).css(settings.type, max + "px");
};
elemsEqual({elements : ['#selector1','#selector2', ... '#selectorN'], type : 'height'});
Well I have this so far:
//Get the height of the right column since it starts at a different Y position than the other two
var right=$('.right').outerHeight(1)-$('.left').children('header').outerHeight(1)-$('.left .innav').outerHeight(1);
//Get the max of the 3
var height_max=Math.max($('.leftCenter').outerHeight(1),$('.rightCenter').outerHeight(), right);
//Apply the max to all 3
$('.rightCenter').height(height_max-3); //-3 to accommodate for padding/margin
$('.right').height(height_max);
$('.leftCenter').height(height_max);
The only problem is that it does not make #newItemsList as tall as the parent, .leftCenter. It also assumes that the right div will be largest, so I don't know if it will still work if it isn't the biggest of the 3.

jQuery - UI Resizable Resize All Child Elements And Its Font-Size

I have been searching the answer for this problem for 1 day, but haven't find it yet!
I want to resize all child elements by calculating and comparing their parent's size with them when their parent is resized and then apply the width and height to every children.
I have writing some lines of codes but this seem not working as expected. The children sizes gone wild with this way:
$('.parentElement').resizable({
resize: function(e, ui) {
var thisw = $(this).outerWidth();
var thish = $(this).outerHeight();
$(this).find("*").each(function(i, elm){
elw = $(elm).outerWidth();
elh = $(elm).outerHeight();
wr = parseFloat(elw) / parseFloat(thisw);
hr = parseFloat(elh) / parseFloat(thish);
w = elw * wr;
h = elh * hr;
$(elm).css({"width": w, "height": h});
});
},
});
Maybe someone can help me to correct my codes above so the resizing of child elements going smoothly!
EDIT:
Here is a fiddle demo.
You can see it that by my code above, the children sizes going wild while I want them to resize smoothly fit with their parent size.
I know I can set the children element's width and height by percentage through jquery or css, but I don't want to do it that way, because text's size cannot be resized to fit container's size by percentage!
The reason why your current code does not achieve your intention of keeping children (and their font size) relatively sized to their parent is that you have no measurement of the original child and parent dimensions/ratios, so you cannot calculate how much their dimensions have changed (and by extension how much you need to change the child dimensions/font size).
One way to avail this information for calculations is to store them in data attributes before any resizing has occurred:
// Storing initial parent CSS
$('.parentElement').each(function(){
$(this).data("height", $(this).outerHeight());
$(this).data("width", $(this).outerWidth());
});
// Storing initial children CSS
$('.parentElement *').each(function(){
$(this).data("height", $(this).outerHeight());
$(this).data("width", $(this).outerWidth());
$(this).data("fontSize", parseInt($(this).css("font-size")));
});
$('.parentElement').resizable({
resize: function (e, ui) {
var wr = $(this).outerWidth()/$(this).data("width");
var hr = $(this).outerHeight()/$(this).data("height");
$(this).find("*").each(function (i, elm) {
var w = $(elm).data("width") * wr;
var h = $(elm).data("height") * hr;
// Adjusting font size according to smallest ratio
var f = $(elm).data("fontSize") * ((hr > wr) ? wr : hr);
$(elm).css({
"width": w,
"height": h,
"font-size": f
});
});
},
});
Now, with each resize of a .parentElement, the ratios of its present versus original dimensions are calculated, then multiplied with the dimensions and font size of its children.
Here's a JSFiddle to demonstrate. Hope this helps! Let me know if you have any questions.

Categories