jsreports version 1.4.27 released with a focus on performance for massive reports

We just released version 1.4.27 of jsreports, and it includes big improvements to report rendering performance. HTML rendering of reports with millions of elements is up to 200% faster, and reports with many nested subreports are up to 500% faster. PDF export is 300-500% faster. Good stuff! We will continuing to add to these performance improvements over time.

If you have a report with hundreds of thousands of sections being rendered in HTML, you can improve scrolling performance by setting enableVirtualRender: true as a config option when calling jsreports.render().

Lots more to come on the features front, but it’ll have to wait for a future blog post.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

What we’re up to

OK, I’ve been getting more and more questions about our roadmap so I thought I’d provide a little color on that here.  While we don’t yet publicly lay out our roadmap in detail, I can give an outline.

Over the next quarter or so we’ve got lots of improvements to the core reporting engine underway.  Some of these are what you’d call nice-to-haves, like font embedding in PDFs.  Some are critical enablers, like internationalization, custom elements, and event hooks.

In parallel with that, we have our first release of server-side rendering (for Node.js) coming up soon which I think is really cool.  We’ll be using that technology to provide a cloud reporting API for developers.

Along with all this we’re working to keep improving the documentation and resources we provide to customers.  We’re also working hard with our OEM customers to make it as easy as possible to embed jsreports, since the demand for that use case has been significant.

So, lots coming in the next few months!  Contact me at emil@jsreports.com for more detail on any of this.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

The new documentation is here!

We’ve been working hard to improve our documentation and our whole documentation-generating system along with it, because we have a lot of new features upcoming and it’s important that we be able to keep the docs up to date as jsreports evolves.

The early results are starting to arrive, and I’m happy to announce a whole new look for the documentation site.  For developers, there are new resources like a reference for our JSON report definition format, and docs for the report builder API.  For end users (people designing reports using the report designer), we’ve got a section just for you that explains how to design reports.

We’re using a new toolchain with some cool open-source pieces to make this documentation system possible, and I’ll probably get around to writing about it one of these days.  In the meantime, check it out and email us at support@jsreports.com with any questions or suggestions.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

New: data table support in report builder API

As you can see in the new bank statement example, jsreports now includes support for data tables defined either in JSON or using the report builder API.  Here’s an example:

jsreports table element example

This table uses nested JSON data, applies a grouping, and then uses CSS to add the borders and bold text.  Cell formats are supplied as configuration properties.  Here’s the code:

.table(0, 1.25, 4.75, 2.5, { data: 'changeItems', hasFooter: true, 
    groupBy: 'category', fontSize: 9, hideRowWhenExpr: '!description' 
})
.column('50%', '   [description]', '', '', { 
    align: 'left', group0Header: '[category]' })
.column('25%', '[currentPeriod]', 'This Period', '[SUM(currentPeriod)]', { 
    align: 'right',
    detailStyle: {
        pattern: '#,##0.00'
    },
    group0Header: '[SUM(currentPeriod)]',
    group0HeaderStyle: {
        pattern: '#,##0.00'
    }
})
.column('25%', '[ytd]', 'Year-to-Date', '[SUM(ytd)]', { 
    align: 'right',
    detailStyle: {
        pattern: '#,##0.00'
    },
    group0Header: '[SUM(ytd)]',
    group0HeaderStyle: {
        pattern: '#,##0.00'
    }
})

We’ll be adding support for tables in the report designer soon.  For now, they’re only available through the API.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

Enhancements to pivot table functionality

Company founder Ebeneezer P. Jsreports has informed us that our bonuses this year will be determined by the number of blog posts we write, so you can look forward to seeing a lot more from me here in the coming months.

Let’s see, what to write about today? Here’s something. We just made some improvements to the pivot engine in jsreports. In case you aren’t familiar, the pivot feature lets you generate columns in a report on the fly from distinct values in the rows of your data source. To use it, check the “enable pivot” box in the designer (under Data & Groups -> Pivot, in the left panel).

report-designer-pivot

You’ll see two areas in the canvas: the non-shaded area between the two purple lines, in the center of the canvas above, is the “pivot column”–this is what will get repeated. You’ll get one copy of this column for each unique value in your pivot field (unless you turn on bucketing, in which case you could get one column for each distinct month, or year, for example).

The other, shaded area in the report is the reserved space for the generated columns. As columns are generated, they’ll fill this space.  If there are too many columns to fit in the shaded space, the report will expand horizontally to fit all columns. Any non-shaded space to the right, and any elements in that space, will be shifted rightward so that they remain in the same position relative to the right edge of the report.

Here’s what happens when you run the report:

jsreports-pivot-output

The pivot column has been repeated left-to-right across the reserved space. The logo remains positioned where it was on the canvas, because it was outside of the repeating pivot column. Each element in the pivot column aggregates the values for its particular grouping and pivot value.

That’s all there is to it. You could put whatever you want in the pivot cells and it will be cloned and any text expressions evaluated against the set of rows that make up that pivot cell.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

How to render PDF directly into an <iframe>

I’m trying to make a point of writing up a quick blog entry whenever I answer an interesting question from a customer. Today, the interesting question was how to render a report into a section of the page, but in PDF format, not HTML. The answer is to use a little-known config option for the jsreports.export method, called outputHandler.

Using outputHandler, you can provide a function that will intercept the resulting PDF blob and do whatever you want.  We normally use this on mobile to generate a download file, but you can also use the blob as the source for a new browser tab or iframe content.  Here’s an example:

jsreports.export({
    format: 'pdf',
    report_def: myReportDef,
    datasets: myDataSources,
    outputHandler: function(pdfBlob) {
        $('.report-output').attr('src', URL.createObjectURL(pdfBlob));
    }
});

You’ll need an <iframe> in order to handle the PDF content, and you should set its type property, like this:

<iframe type="application/pdf" class="report-output"></iframe>

And here’s what it looks like in Chrome:

jsreports-demo-pdf-to-iframe

 

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

New features! Page breaks and subreports

It’s been a while since the last update — things have been busy here.  But today I get to announce a couple of great new features: page breaks and subreports.

jsreports page break and subreport elements

The page break element gives you control over where pages break in PDF output mode.  Just drag it to the right place in your report template, and you’ll get corresponding page breaks in the PDF.  You can set the “every Nth record” property to only break after a certain number of records.

The subreport feature lets you embed a report within another report.  When you add the subreport to the canvas in the designer, you can jump directly into the subreport to edit it.  You can link data between outer report and the subreport by matching field values, too.

jsreports subreport element options

We’ve got a bunch of other work in progress that I’ll write about soon.  If you have specific feature requests or want to know more about these new features, email us at support@jsreports.com.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

Our first plugin for the report designer

I get requests from customers for features that would make great additions to jsreports but that not everyone will need.  For things that aren’t core product features, we’ve been working on the idea of plugins–extra modules you can load individually as needed.

Today as part of version 1.2.37 we’re including our first ever plugin: a report selector for the designer.  Previously, as the developer, you had to specify a single report template whenever a designer was opened.  Now, you can provide a list of reports and allow the user to switch between them, and optionally create new reports and delete them too.

reportlist-plugin-demo

You can use the plugin by specifying it in the plugins config property of the designer, like this:

var designer = new jsreports.Designer({
    embedded: true,
    container: $(".report-designer-container"),
    dataSources: data,
    report: null,
    showDownloadButton: true,
    plugins: [{
        pluginType: 'ReportList',
        reports: [ report1, report2 ],
        listeners: {
            "deletereport": function(evt, report) {
                // TODO handle report deletion here
            }
        }
    }]
});

Full documentation for the plugin is here: ReportList plugin API docs

For this first plugin, we’ll be including it as part of the main jsreports distribution.  As the collection of plugins grows we’ll begin to bundle them separately.

Got ideas for plugins?  Let us know.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

Improvements to Jasper Reports support on the way

Just FYI, we’ve been getting a few requests lately for increased compatibility with Jasper Reports.  We’re working on it!

It’s not likely we’ll support every nook and cranny of the Jasper Reports feature set, since our goals are not identical with Jasper Reports, but we think we can do a solid job of making our report designer handle the most common features people are using.

First up is enabling our designer to open Jasper Reports’s .jrxml file format.  Right now, we can go from our JSON format to .jrxml but not the other way.  That means that right now you can create brand new reports and send them to Jasper, but you can’t yet modify existing reports that you’ve got in the Jasper format.

If you have Jasper Reports .jrxml reports you’re using today and you’d like to add a report designer into your web application to let your end users modify and customize their own reports, shoot me an email so I can make sure we cover your use case.

Photo of a bus

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications

Testing generated binary files with CasperJS / PhantomJS

Tinkering with CasperJS today to see if we can use it in our testing pipeline. Turns out it’s not that easy in PhantomJS to handle binary files generated in the browser, like the PDF and Excel files generated by jsreports. Here’s the solution that finally worked:

casper.on('page.initialized', function(page) {
    page.evaluate(function() {
        window.saveAs = function(blob) {
            var reader = new FileReader();
            reader.onloadend = function() {
                window.callPhantom(reader.result);
            }
            reader.readAsBinaryString(blob); 
        };
    });
    page.onCallback = function(binaryStr) {
        var fOut = fs.open('download.pdf', 'wb');
        fOut.write(binaryStr);
        fOut.close();
    };
});

We inject a custom window.saveAs into the browser, which jsreports will find and use automatically; that function turns the Blob into a string and passes it out to PhantomJS via callPhantom. Back in PhantomJS, we write the string to a binary file in the test directory.

JavaScript enthusiast at jsreports – building a better reporting solution for modern web applications