Center visualize.js div content on page - javascript

I have been trying to get a report that we have built with jasperreports and rendered via visualize.js to be centered horizontally on a page (regardless of the page or browser dimensions).
My current code is:
<!DOCTYPE html>
<html>
<head>
<script src="https://mobiledemo.jaspersoft.com/jasperserver-pro/client/visualize.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.5.1/mootools-core-full-compat.min.js"></script>
<script type='text/javascript'>
window.addEvent('load', function() {
visualize({
auth: {
name: "joeuser",
password: "joeuser",
organization: "organization_1"
}
}, function(v) {
//render dashboard from provided resource
v("#container").report({
resource: "/public/Samples/Reports/06g.ProfitDetailReport",
scale: "container",
error: handleError
});
//show error
function handleError(err) {
alert(err.message);
}
});
});
</script>
<style>
html,
body {
height: 100%;
width: 100%;
margin: 0 auto;
background-color: #000000;
}
#container {
display: block;
width: 100%;
height: 100%;
border: 0px;
margin: 0 auto;
background: blue;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
</html>
The following fiddle should show the current issue:
https://jsfiddle.net/g207h68x/
If you resize the result window, you can see that as the report is scaled (via the scale:"container" entry in the render function it sticks to the left of the screen.
I can't use any specific sizes for the <div> as each dashboard has their own unique dimensions depending on what is being displayed in the report or dashboard (some may be 300x500 and others may be up to 1920x1080).
I have tried to wrap the <div> inside flexboxes which didn't seem to help..unless I was not doing it correctly (entirely possible).
Another approach was to try and nest the div within a parent div, but that didn't seem to work either (again, I may have not done it correctly either).
I have also tried to make the <div> an inline-block, but that seems to throw off the scaling entirely for visualize.js as it reads the container dimensions (I think).
I looked into the visualize.js documentation, but there is really not much there for dynamic sizing and spacing on the page.
I even tried to put the <div> within a table...but that didn't seem to help as the table cells would just span across the page or container.
I did read somewhere that the JQuery UI can be used to further manipulate what visualize.js is doing, but I could not find any examples or references on where that was documented.
If anyone knows how to center this type of content, I would greatly appreciate your input.
Thank you in advance.

The centering does not work in your jsfiddle because the report gets scaled inside the container and its transform-origin is set to top left. To overcome most of the issues I have come up with the following script based on the one you posted.
The main idea is to add some margins to the ".jrTable" table with the beforeRender event, then to intercept the CSS transform-origin from within visualize.js and set the new one.
Please note that this is not a complete script and does not work on some narrow window setups. I did not run it on a dashboard either.
You will have to decide when to set this new origin based on some measurements. Also, the jQuery's cssHook will probably need adjustments for different vendor prefixes if you intend to target other browsers. I tested it only in Chrome and Safari with the default one. More info on jQuery cssHooks.
EDIT: It seems that the initial solution based on changing the margin and the transform-origin produces unpredictable results and does not scale correctly in all cases. Keeping it for reference here, though.
Better results can be achieve just by adjusting the offset after the transform-origin is applied:
window.addEvent('load', function() {
var hookRegistered = new $.Deferred();
var $container = $("#container");
function adjustPageOffset($jrPage) {
var pageWidth = $jrPage[0].getBoundingClientRect().width,
containerWidth = $container.width();
(pageWidth<containerWidth) ? $jrPage.offset({left:(containerWidth-pageWidth)/2}) : $jrPage.offset({left:0});
}
__visualize__.require(["jquery"], function($) {
$.cssHooks["transformOrigin"] = {
set: function( elem, value ) {
elem.style["transformOrigin"] = value;
if ($(elem).is(".jrPage") && "top left" === value) {
adjustPageOffset($(elem));
}
}
};
hookRegistered.resolve();
});
// wait for the hook to register in visualize's embedded jQuery
// then load the report
hookRegistered.then(function() {
visualize({
auth: {
name: "joeuser",
password: "joeuser",
organization: "organization_1"
}
}, function (v) {
//render dashboard from provided resource
v("#container").report({
resource: "/public/Samples/Reports/06g.ProfitDetailReport",
scale: "container",
error: handleError
});
//show error
function handleError(err) {
alert(err.message);
}
});
});
});
And the modified jsfiddle.

Related

How do I make the entire tingle modal containing an image visible on load?

On load and if browser width is greater than 540px, the modal containing an image is cut-off (see figure below). What should I do to make the vertical scroll-bar immediately appear?
This existing project that I'm working on is using tingle modal plug-in. It is linked like so:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="tingle.min.css">
<style>
html, body {
height: 100%;
}
img {
height: auto;
width: 100%;
}
</style>
<title>Tingle Modal</title>
</head>
<body>
<script src="tingle.min.js"></script>
<script src="modal.js"></script>
</body>
</html>
modal.js is where I create the modal containing the image:
function createModal(content) {
let $modal = new tingle.modal({
footer: false,
stickyFooter: false,
closeMethods: ["overlay", "button", "escape"],
closeLabel: "Close",
cssClass: ["modal"],
beforeClose: function() {
return true; // close the modal
},
onClose: function() {
$modal.destroy();
}
});
$modal.setContent(content);
$modal.open();
}
createModal("<div id='modal'><img id='sample' src='sample.jpg' /></div>");
console.log(document.getElementById("sample").offsetHeight);
I noticed that when you zoom-in or zoom-out, or resize the browser, I then get the expected behavior of having the scroll-bar. I also noticed that on load, the image height is 0. I can't set the image height to a pixel value because I'll have several modals containing different images that vary on sizes.
You can also see the behavior here: CodeSandbox. Please do make the embedded browser width in CodeSandbox bigger first, then refresh to see what I mean.
I have tried the following. But it then adds the scroll bar even when the entire modal fits in 100vh, which is not desirable.
.tingle-modal {
overflow-y: scroll;
}
Try adding these styles
.tingle-modal {
overflow-y: auto;
}
If you need to save the position of the close button, then add:
.tingle-modal__close {
position: sticky;
align-self: end;
}
And instead of
createModal("<div id='modal'><img src='sample.jpg' /></div>");
use it
const img = new Image();
img.onload = () => {
createModal("<div id='modal'><img src='sample.jpg' /></div>");
};
img.src = "sample.jpg";
I looked at the code in tingle.min.js. It checks if the height of the modal overflows, if so, it adds a tingle-modal--overflow class. However, the image isn't loaded yet when it checked the height. So I had to redo the checking after calling the createModal function like so:
document.getElementsByTagName("img")[0].onload = function() {
const $modal = document.getElementsByClassName("tingle-modal")[0];
if (window.innerHeight <= $modal.clientHeight)
$modal.classList.add("tingle-modal--overflow");
};
Here's a jQuery version of the solution:
$(".tingle-modal-box img").on("load", function() {
const $modal = $(".tingle-modal");
if (window.innerHeight <= $modal.height())
$modal.addClass("tingle-modal--overflow");
});

How to use IntersectionObserver API to make navBar sticky

I am making the clone of a webpage which is made in JS but I am developing it by HTML, CSS, JS. Its navBar looks like this . Here is the link if you want to experience yourself link.
So, I have tried to implement this using IntersectionObserver API as well as by using window.addEventListener(). I don't want to implement this by using scroll event Listener because it is too heavy for end user.
const intersectionCB = ([entry]) => {
const elem = entry.target;
if (!entry.isIntersecting) {
elem.classList.add('nav__2-sticky');
// observer.unobserve(navBar);
} else {
elem.classList.remove('nav__2-sticky');
}
};
const observer = new IntersectionObserver(intersectionCB, {
root: null,
threshold: 0
});
observer.observe(navBar);
In HTML file
<div class="nav__2">
<div class="row nav__2--content">
<div class="logo-container">
<img src="img/logo-black.png" alt="" class="logo" />
</div>
........
In SCSS file
.nav {
&__2 {
top: 8rem;
position: absolute;
left: 0;
width: 100%;
&-sticky {
position: fixed;
top: 0;
}
}
}
You might understand what is happening. When navBar gets out of the view, (navBar is positioned at 8rem from top!). I append nav__2-sticky class (which is positioned fixed at 0 from top) to appear on the screen. Due to which entry.isIntersecting becomes true and elem.classList.remove('nav__2-sticky'); is executed. As a result navBar again gets out of the view and again elem.classList.add('nav__2-sticky') is executed. This cycle of adding and removing classes due to entry.isIntersecting becoming True and False is creating a problem for me. This happens in such speed that it shows abnormal behaviour.
So, is there any proper solution for this? I would also like to hear other solutions that might work.
I used scroll event after all. Here is the code, I think I don't need to explain. You will get more detailed explanation here link
const initialCords = navBar.getBoundingClientRect();
document.addEventListener('scroll', () => {
if (window.scrollY > initialCords.top) {
navBar.classList.add('nav__2-sticky');
} else {
navBar.classList.remove('nav__2-sticky');
}
});
Another angle could be to run the intersection observer on an element that is out of view (below the bottom of the screen) and not only the navbar itself

how to export the 'hidden div' element as PDF without showing it on the UI

Please consider the following hidden div element. I am using it as a hidden element to construct the PDF contents and trying to download as PDF.
HTML elements declared as below.
<div id="griddata" style="display:none;">
<div id="reportHeader" style="display:none;">
Consider other elements that I want to show in the PDf here
</div>
</div>
And below is the Kendo Export chart as PDF code, Which I will call through the LoadPDF function.
function LoadPDF() {
try {
$("#griddata").show();
$("#reportHeader").show();
if ($("#chartDiv").html() != null && $("#griddata").html() != '') {
setTimeout(function () {
kendo.drawing.drawDOM($("#griddata"))
.then(function (group) {
// Render the result as a PDF file
return kendo.drawing.exportPDF(group, {
paperSize: "auto",
margin: { left: "1cm", top: "1cm", right: "1cm", bottom: "1cm" }
});
})
.done(function (data) {
// Save the PDF file
kendo.saveAs({
dataURI: data,
fileName: window.sessionStorage.getItem('XXXName') + ".pdf",
proxyURL: "/Account/Export"
});
$("#reportHeader").hide();
$("#griddata").hide();
});
}, 2000);
}
}
catch (e) {
$("#reportHeader").hide();
$("#griddata").hide();
UMGenerateAlert('Error while exporting data');
}
finally {
}
}
The above method works fine, but the problem is, before exporting the "griddata" div elements as PDF, I am forced to ENABLE the div. Otherwise the exported PDF returns no data. This causing the "griddata" div to appear on the screen till the PDF gets exported and gets hidden once the document is downloaded.
Please suggest me how we can handle this, without displaying it in the UI.
Try CSS Print Media Query:
#media print {
/* All your print styles go here */
#header, #footer, #nav { display: none !important; }
#griddata, #reportHeader { display: block !important; }
}
Or the old way:
<link href="/print.css" rel="stylesheet" media="print" type="text/css" />
Regarding the grid part, have you already tried using visibility: hidden;? since the space and dimensions of the element are preserved.
If I were you, I would just show an overlay layer with a loading progress bar that covers the grid area and hide it after finish hidding the grid.
Anyway, display: none is still part of the DOM, I'll update my answer if there is a workaround.
I just came across similar question myself couple days ago and got it working based on this answer, which is to overlay your pdf div with another div. Here render-pdf is the div where your kendo pdf gets loaded.
<div id="pdf-with-overlay" style="position: relative; width: 100%;">
<div id="render-pdf"></div>
<div id="pdf-overlay" style="width:100%;height:100%;position: absolute;top:0;left:0;z-index:10;"></div>
</div>
PS. In the scenario I mention I do an overlay instead of hiding, as found hiding also has some limitations e.g. if you want to draw pdf to canvas, hidden one will show no content.

How to center a handsontable properly

I am using handsontable and I would like to show a table centered in the page or a div.
I have managed to do this by changing the width of the container div after the table is initiated (see snippet). However this seems cumbersome.
$(document).ready(function () {
var container = document.getElementById('basic_example');
var hot = new Handsontable(container, {
data: Handsontable.helper.createSpreadsheetData(10, 12),
colHeaders: true,
rowHeaders: true,
afterInit: function () {
$("#basic_example").css("width", $("#basic_example .wtHider").css("width"))
}
});
});
#basic_example {
margin-left: auto;
margin-right: auto;
}
<link href="http://handsontable.com//styles/main.css" rel="stylesheet">
<link href="http://handsontable.com//bower_components/handsontable/dist/handsontable.full.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://handsontable.com//bower_components/handsontable/dist/handsontable.full.min.js"></script>
<div id="basic_example"></div>
Is there an easy/better way of centering a handsontable?
Using your work-around, I would recommend using afterRender instead of afterInit in order to update the size of your table whenever the handsontable is rendered.
This would be especially useful if the user changes the size of the screen, if you allow the addition of columns or rows, or if there are other possibilities of the table changing sizes after the original initialization.
Based on the earlier answers, I used the afterRender (and afterChange) events as follows:
afterRender: function () {
let wtHider = document.querySelector('#tableContainer .wtHider');
container.style.width = wtHider.style.width
},
However, when you hide a column, it seems that afterRender is fired too early, before the element with the wtHider class is updated.
Adding a delay of 0 ms solves this issue:
afterRender: function () {
let wtHider = document.querySelector('#tableContainer .wtHider');
setTimeout(() => {
container.style.width = wtHider.style.width
}, 0);
},
Note: Tested using chromium version 87.0.4280.66, Ubuntu 20.04 and handsontable 8.2.0

Scroll event background change

I am trying to add a scroll event which will change the background of a div which also acts as the window background (it has 100% width and height). This is as far as I get. I am not so good at jquery. I have seen tutorials with click event listeners. but applying the same concept , like, returning scroll event as false, gets me nowhere. also I saw a tutorial on SO where the person suggest use of array. but I get pretty confused using arrays (mostly due to syntax).
I know about plugins like waypoints.js and skrollr.js which can be used but I need to change around 50-60 (for the illusion of a video being played when scrolled) ... but it wont be feasible.
here is the code im using:-
*
{
border: 2px solid black;
}
#frame
{
background: url('1.jpg') no-repeat;
height: 1000px;
width: 100%;
}
</style>
<script>
$(function(){
for ( i=0; i = $.scrolltop; i++)
{
$("#frame").attr('src', ''+i+'.jpg');
}
});
</script>
<body>
<div id="frame"></div>
</body>
Inside your for loop, you are setting the src attribute of #frame but it is a div not an img.
So, instead of this:
$("#frame").attr('src', ''+i+'.jpg');
Try this:
$("#frame").css('background-image', 'url(' + i + '.jpg)');
To bind a scroll event to a target element with jQuery:
$('#target').scroll(function() {
//do stuff here
});
To bind a scroll event to the window with jQuery:
$(window).scroll(function () {
//do stuff here
});
Here is the documentation for jQuery .scroll().
UPDATE:
If I understand right, here is a working demo on jsFiddle of what you want to achieve.
CSS:
html, body {
min-height: 1200px; /* for testing the scroll bar */
}
div#frame {
display: block;
position: fixed; /* Set this to fixed to lock that element on the position */
width: 300px;
height: 300px;
z-index: -1; /* Keep the bg frame at the bottom of other elements. */
}
Javascript:
$(document).ready(function() {
switchImage();
});
$(window).scroll(function () {
switchImage();
});
//using images from dummyimages.com for demonstration (300px by 300px)
var images = ["http://dummyimage.com/300x300/000000/fff",
"http://dummyimage.com/300x300/ffcc00/000",
"http://dummyimage.com/300x300/ff0000/000",
"http://dummyimage.com/300x300/ff00cc/000",
"http://dummyimage.com/300x300/ccff00/000"
];
//Gets a valid index from the image array using the scroll-y value as a factor.
function switchImage()
{
var sTop = $(window).scrollTop();
var index = sTop > 0 ? $(document).height() / sTop : 0;
index = Math.round(index) % images.length;
//console.log(index);
$("#frame").css('background-image', 'url(' + images[index] + ')');
}
HTML:
<div id="frame"></div>
Further Suggestions:
I suggest you change the background-image of the body, instead of the div. But, if you have to use a div for this; then you better add a resize event-istener to the window and set/update the height of that div with every resize. The reason is; height:100% does not work as expected in any browser.
I've done this before myself and if I were you I wouldn't use the image as a background, instead use a normal "img" tag prepend it to the top of your page use some css to ensure it stays in the back under all of the other elements. This way you could manipulate the size of the image to fit screen width better. I ran into a lot of issues trying to get the background to size correctly.
Html markup:
<body>
<img src="1.jpg" id="img" />
</body>
Script code:
$(function(){
var topPage = 0, count = 0;
$(window).scroll( function() {
topPage = $(document).scrollTop();
if(topPage > 200) {
// function goes here
$('img').attr('src', ++count +'.jpg');
}
});
});
I'm not totally sure if this is what you're trying to do but basically, when the window is scrolled, you assign the value of the distance to the top of the page, then you can run an if statement to see if you are a certain point. After that just simply change run the function you would like to run.
If you want to supply a range you want the image to change from do something like this, so what will happen is this will allow you to run a function only between the specificied range between 200 and 400 which is the distance from the top of the page.
$(function(){
var topPage = 0, count = 0;
$(window).scroll( function() {
topPage = $(document).scrollTop();
if(topPage > 200 && topPage < 400) {
// function goes here
$('#img').attr('src', ++count +'.jpg');
}
});
});

Categories

Resources