Solved

Improving the previewer experience


Userlevel 5
Badge +15

We're currently using the Web GUI and the (DocUltimate) previewer component. What we do is showing a preview of a subject. This preview is a SVG-document, which the previewer component converts to a PDF file, and previews. We use this especially because of the zoom functionality. We've received some feedback of our end users that the previewer is too slow. What they do is they open a record, check the preview and continue on to the next one (it's a grid + a preview). Caching is useless in this process, as it's most likely the document will be opened only once.

Now the problem is that I somehow want to increase the performance, or better said, the user experience. Currently it's not loaded 'with a blink of the eye'. Causes of this can be:

- Not enough resources on the server
- The convertion from SVG to PDF that DocUltimate has to do
- The contents of the SVG

These cases we've tested and try to influence. We scaled the Azure environment up, but you'll still see the loading image spinning, and doesn't affect the performance. We've also tried direct PDF files in stead of the SVG's, but still no performance increase. We did find out the contents of the SVG affect the performance and we've applied a trick here that affects it (by scaling it down in sizes to fit with the window width). But problem is that the user can define the content of this preview, so it still can be really large. You simply don't know what the user does. And although that's applied, it's still not fast enough in the eyes of the end user.

So, we're looking to alternatives, or fixes.

Because it's actually a SVG document, it could be perfectly an HTML component which could be embedded. Problem is that this cannot be zoomed in and out, which is mandatory. And it cannot be set to full screen, which is also mandatory. I say it cannot be zoomed, because we've tried to embed some JavaScript libraries (https://github.com/ariutta/svg-pan-zoom) but they are stripped away by the HTML control.

So are there any suggestions? I was thinking of going for the 'html component' way, which sounds the most 'light' solution, only it doesn't has the required zoom / full screen features. Even if JavaScript is allowed, I am not sure if it's possible. Another idea is embed it as an url. So that the preview is generated by a web service or so. The column value is for example https://my-service.site/generate?data=base64data. Just an idea, don't know if it's possible.
 

icon

Best answer by Jasper 3 April 2020, 16:09

View original

11 replies

Userlevel 7
Badge +11

Hi Rene,

Unfortunately, there’s not much we can do to further improve the performance of the DocumentUltimate component that we use in the Web GUI, besides pre-caching. 

A possible alternative to display a zoomable SVG would be to create your own HTML page with, for example, the SVG pan/zoom JavaScript library you mentioned, and display that page using an URL control in the preview component of the Web GUI.

The HTML page should download the SVG file itself using the Web GUI ImageHandler, using a request similar to this:

https://server/webgui/ImageHandler.ashx?type=tsffile&controllerId=[table]_1&objPropId=[column]

This would download the file in column [column] of table [table] for the currently displayed record. You can get the exact URL by showing the SVG file in an image control and monitor the requests fired by the Web GUI in the browsers’ Developer tools.

Note that the HTML page should be hosted on the same domain because of CORS.

Userlevel 5
Badge +15

Hi Jasper,

I'm trying to apply the alternative but I got lost in how the ImageHandler.ashx works. I did find out that it'll display the first record in the subject, but not the next records (it gives a HTTP 403 Forbidden error).

To test it, I've set up the table part (part_id int, preview nvarchar(max), preview_storage varbinary(max)). The column 'preview' is of control type 'Image upload' (also tested 'File upload'). I've also added an expression column (preview_url, of control type 'Url'), to simulate the url using the value 'http://localhost/sandbox/preview/preview.html?file=' + t1.preview + '&ext=.html'. By using a variant (grid + preview lay-out) I display only the 'Url' control, so the Web GUI will pick up the 'Url' als 'Preview'.

The url in the expression is a bit of a hack, I've added &ext=.html to enable the proper previewer, because if t1.preview ends with .svg, it shows the DocUltimate previewer. The preview.html contains the following:

<html>
<head>
    <title>Preview</title>
    <script src="jquery-3.4.1.min.js"></script>
    <script>
    $(document).ready(function () {
        $.get({
            url: "http://localhost/sandbox/ImageHandler.ashx?type=tsffile&controllerId=part_0&objPropId=preview&filename=" +window.location.href.slice(window.location.href.indexOf('?') + 1).split('=')[1].split('&')[0] ,
            //cache: false
        }).then(function(rdata){
            console.log(rdata);
            console.log(rdata.documentElement.outerHTML);
            var thing = $(rdata.documentElement.outerHTML);
            $('#content').append(thing);
        });
    });
    </script>
</head>
<body >
    <h1 id="test">Preview test</h1>
    <div id="content"></div>
</body>
</html>


This works for the first record selected, but for the next record, the 403 error pops up in the console. Replacing the url with the direct url doesn't work either (http://localhost/sandbox/ImageHandler.ashx?type=tsffile&controllerId=part_0&objPropId=preview&filename=circle.svg). This also results in a 403. 
It could be the way I'm retrieving the data with jQuery is wrong, I don't know. I don't exactly how the file ImageHandler.ashx works and how it determines what to display, which is a bit of magic to me. Any clues on how to fix this? I’ve also noticed sometimes there is a parameter named filename, I don't know if it necessary or if it affects thing.


Note: I've also tried hosting it externally, passing the document in the GET parameter. This works, only the problem here is that a GET parameter / URI has a size limit, which is most likely to be exceeded, even when applying compression.

Although this would be the best solution for us I think: It doesn't require storage at the database and the previews are generated externally and it's completely isolated. If the preview for example gets an update (new line colours for example), it's not needed to update the database, only the web api serving the image. I had a solution in my mind using process flows for replace the GET with a POST, but I don't know it's possible. The case is that on each record change, a web call should be performed using POST and returning the value in a column of the current record.

Userlevel 7
Badge +11

Hi Rene,

I can’t tell by your description why you are getting these 403 errors.

This is how I got it working though:

Model

HTML file

<html>
<body >
My custom preview:

<img id="myImg" src="" />

<script>
var d = new Date();
var url = "/webgui/ImageHandler.ashx?type=tsffile&controllerId=preview_url_0&objPropId=image_upload" + "&ver=" + d.getTime();
document.getElementById("myImg").src = url;
</script>
</body>
</html>

The imagehandler will always return the corresponding file for the current row, so there is no need to provide the filename. I’ve added a timestamp to the url to make sure the browser doesn’t cache the image. (You could use the filename for that, but that can cause problems with images with the same name.) 

Result

 

A note: the number in the controllerId changes if open the same subject multiple times. We’re working on a solution for that.

Userlevel 7
Badge +11

The next release of the Web GUI will feature the option to pass the controllerId of the current subject to the preview component, by replacing any [controllerId] string in the URL with the actual Id.

The URL would be something like this:

/preview/preview.html?controllerId=[controllerId]

And the JavaScript to extract the controllerId and create the ImageHandler URL:

var time = new Date().getTime();
var controllerId = new URLSearchParams(window.location.search).get('controllerId');
var src = `/TSF_ASP_dotNET/ImageHandler.ashx?type=tsffile&controllerId=${controllerId}&objPropId=image_upload&ver=${time}`;
document.getElementById("myImg").src = src;

 

Userlevel 5
Badge +15

I’ve got it working in a test environment :-). The first results look promising, speed is getting more acceptable and with the use of the svg-pan-zoom library it's also more user friendly regarding the zooming with scroll.

I also found out what is partially causing the http 403 error, it occurs when closing the browser tab page (or tab refresh) and then logging in again via this screen:
 

If the user logs in here again, the 403 Forbidden occurs. Something with sessions / cookies, I don't know.

I still do have some weird occurences of a 403 after a fresh login, but I don't know yet how that occurs.

What also is important is having the right column order, I had some issues with that causing problems. The ‘url’ component must be first.

<html>
<head>
<title>Preview</title>
<style>
body {
overflow: hidden; /* Hide scrollbars */
}</style>
<script src="jquery-3.4.1.min.js"></script>
<script src="svg-pan-zoom.min.js"></script>
<script>
$(document).ready(function () {
var d = new Date();
$.get({
url: "/sandbox/ImageHandler.ashx?type=tsffile&controllerId=part&objPropId=preview&ver=" + d.getTime(),

}).then(function(rdata){
var thing = $(rdata.documentElement.outerHTML);
$('body').append(thing);

var svg = document.getElementById('svg-part');
svg.setAttribute('height', window.innerHeight - 20);
svg.setAttribute('width', window.innerWidth - 20);
svgPanZoom(svg);
}).fail(function(rdata){
var thing = $('<p>Your session expired, please log off and log in again to show the previewer.</p>');
$('body').append(thing);
});
});
</script>

</head>
<body>
</body>
</html>

 

Userlevel 5
Badge +15

I'm trying to apply the previewer to a second subject, which works, but when switching back (and vice versa) to the first subject, the ImageHandler.ashx gives again a http 403 error. Any clues / suggestion on that? I don't exactly know how the magic in ImageHandler.ashx works. The user can now only preview 1 of 2 subjects and needs to log off when he wants to preview the other subject.

Userlevel 7
Badge +11

There really isn’t much magic in the ImageHandler; it will just return the image of the given column for the current row of the specified controller. If the controller or the column is not found, it will return a 403.

I suggest to wait for the next release of the Web GUI (scheduled for Tuesday), so you can pass the right controllerId to the preview page and see if that solves the problem. 

Userlevel 5
Badge +15

There really isn’t much magic in the ImageHandler; it will just return the image of the given column for the current row of the specified controller. If the controller or the column is not found, it will return a 403.

I suggest to wait for the next release of the Web GUI (scheduled for Tuesday), so you can pass the right controllerId to the preview page and see if that solves the problem. 

Having a 403 Forbidden sounds a bit odd, if something is not found I would expect a 404 Not Found.

And the weird thing is that they are found initially. Lets say I have the subject named ‘Cars’ with a list of car brands and logos. If I open this first, a preview of a Car brand logo will be shown. Then I open the subject ‘Countries’, with a list of flags. When I open this subject, I get a 403 Forbidden.

But when I log off, log in again, open the ‘Countries’ first, the flags (images) will be shown. When I open the other subject ‘Cars’, then I get there the 403 Forbidden. But in the first session I've seen a car brand, so it's weird that by switching subjects it is suddenly not found.

So I do think it's something with the (browser) session (because it's a 403, and not a 404).

I hope the next release will fix this, I'll wait.

Userlevel 5
Badge +15

There really isn’t much magic in the ImageHandler; it will just return the image of the given column for the current row of the specified controller. If the controller or the column is not found, it will return a 403.

I suggest to wait for the next release of the Web GUI (scheduled for Tuesday), so you can pass the right controllerId to the preview page and see if that solves the problem. 

I've tried the new 2020.1.15 release of the web gui but unfortunately it didn't solve my problem. But I did notice something that could cause my problems, and it's indeed the unknown number added to the controllerId.

I've done a test with my test case above (car brands, country flags). I noticed the number in the controllerId changes, and that causes my 403 errors.

Removing this part (i.e. car_0 or car_3 strip off the _0 or _3 part) doesn't work either. It does require a vague number retrieved by the Chrome developer tools.

Is it possible to lock, remove or calculate this number?

Userlevel 7
Badge +11

You can pass the correct controllerId to your preview page by adding a [controllerId] variable to the URL; see my previous post here.

Doesn't that solve the problem? 

Userlevel 5
Badge +15

You can pass the correct controllerId to your preview page by adding a [controllerId] variable to the URL; see my previous post here.

Doesn't that solve the problem? 

Ah, that makes sense, I didn't understand it properly. It works :smiley: !

 

Reply