Closed raf18seb closed 2 years ago
Dear highcharts representatives, any progress on this?
@cvasseng , any comment? Async problems maybe?
Did you pass it as written? If so, try formatting as JSON instead of JavaScript:
{
"chart": {
"type": "bubble",
"plotBackgroundImage": "https://www.highcharts.com/samples/graphics/skies.jpg"
},
"xAxis": {
"min": 0,
"max": 1.3
},
"yAxis": {
"min": 0,
"max": 70
},
"series": [{
"color": "yellow",
"name": "Sun",
"data": [{
"x": 1,
"y": 55,
"z": 0
}]
}]
}
If that still doesn't work, please try the latest version 2.0.19
which seems to produce the correct result on my local test setup.
Reviving this topic. This JSON doesn't produce a background image on the Export Server test page either: https://export.highcharts.com/
@highcharts - any ideas?
I'm facing the same issue here - Node export server is not able to process neither .png nor base64 images.
Reproduction steps I use highcharts-export-server --infile test.json In test.json file I have this config like this:
{
chart: {
type: 'bubble',
plotBackgroundImage: 'https://www.highcharts.com/samples/graphics/skies.jpg'
},
xAxis: {
min: 0,
max: 1.3
},
yAxis: {
min: 0,
max: 70
},
series: [{
color: 'yellow',
name: 'Sun',
data: [{
x: 1,
y: 55,
z: 0
}]
}]
}
highcharts-export-server v2.0.24 node v8.16.1
@highcharts - How can we fix that?
+1
any response @highcharts?
Just debugged, it seems that the reason lies in.. Highcharts core. Exporting server expects chart.events.load
to be called after all images are loaded. In fact, that applies to all symbol
-like generated images (e.g. markers), but does not work with other images (e.g. plotBackgroundImage
).
Workaround is to create a dummy series with marker that will load the image, snippet with explanation:
{
"chart": {
"type": "bubble",
"plotBackgroundImage": "https://www.highcharts.com/samples/graphics/skies.jpg"
},
"series": [{
// Dummy series, that is rendered under the actual one
"type": "scatter",
// Hidden from legend
"showInLegend": false,
"marker": {
// Visible, but hidden
"radius": 0.0001,
// Path to image we want to use
"symbol": "url(https://www.highcharts.com/samples/graphics/skies.jpg)"
},
"data": [] // copy of one point in original series
}, {
"color": "yellow",
"name": "Sun",
"data": [{
"x": 1,
"y": 55,
"z": 0
}]
}]
}
Working example:
{
"chart": {
"type": "bubble",
"plotBackgroundImage": "https://www.highcharts.com/samples/graphics/skies.jpg"
},
"xAxis": {
"min": 0,
"max": 1.3
},
"yAxis": {
"min": 0,
"max": 70
},
"series": [{
"type": "scatter",
"showInLegend": false,
"marker": {
"radius": 0.0001,
"symbol": "url(https://www.highcharts.com/samples/graphics/skies.jpg)"
},
"data": [{
"x": 1,
"y": 55
}]
}, {
"color": "yellow",
"name": "Sun",
"data": [{
"x": 1,
"y": 55,
"z": 0
}]
}]
}
Aha! I'm using the background image for a polar chart, so just set the marker in the dummy series to show centered on the chart and plotted the actual series on top of that. Completely avoided using plotBackgroundImage (I'm exporting to pdf so don't need any live behaviour). Works like a charm.
Thanks @pawelfus !
I'm facing a similar issue. The SVGs are loaded like 2 times out of 10 when used in the markers:
"series": [
{
"type": "line",
"lineWidth": 0,
"data": [
{
"x": 1592586000000,
"y": 86,
"marker": {
"symbol": "url(https://dots.dataontouchdev.com/images/weather/yr_weather_symbols/svg/01d.svg)",
"width": 40,
"height": 40
}
},
...
Just to avoid answering in every ticket (#43 and #238), I will just answer here. Is that ok with you @100phel ? I believe, there's no point to copy my answer in every ticket.
Just tested my solution above - you are right, sometimes it fails. After some tests it seems ~30% of the exported charts didn't include images properly. I don't know the reason. This seems to be happening only when exporting chart from JSON options, SVG seems to be fine..
There's an alternative solution - add resources and force chart to wait for loading all images, like this:
highcharts-export-server --infile test.json --resources '{ "files": "test.js", "asyncLoading": true }'
And test.js
file:
function checkImages() {
if (Array.prototype.filter.call(document.images, function(img) { return !img.complete }).length === 0) {
highexp.done();
} else {
setTimeout(checkImages, 0);
}
}
setTimeout(checkImages, 0);
With this workaround, it's no longer necessary to create a dummy series.
@pawelfus Thank you for your time testing this but your solution still doesn't work for me.
checkImages
does get called - I've checked that by adding one line to your code:
function checkImages() {
if (Array.prototype.filter.call(document.images, function(img) { return !img.complete }).length === 0) {
throw new Error('Images: ' + JSON.stringify(document.images))
highexp.done();
} else {
setTimeout(checkImages, 0);
}
}
setTimeout(checkImages, 0);
And the output is:
phantom worker 1 unexpected data - Error: Images: {"length":0}
So, it seems like document doesn't contain any images and that's why highexp.done()
gets called right away. And I still don't get any symbols on the chart.
Here's my json file:
{
"title": "Observation Forecast - Luke Lightfoot",
"xAxis": [
{
"type": "datetime"
}
],
"yAxis": [
{
"title": {
"text": "Temperature"
}
}
],
"series": [
{
"type": "line",
"lineWidth": 0,
"data": [
{
"x": 1592888400000,
"y": 73,
"marker": {
"symbol": "url(https://dots.dataontouchdev.com/images/weather/yr_weather_symbols/svg/22n.svg)",
"width": 50,
"height": 50
}
}
],
"showInLegend": false
}
],
"asyncRendering": true,
"resources": {
"files": "resources.js"
}
}
And here's the video just in case: https://www.awesomescreenshot.com/video/251118?key=53fb64c0330b20760898eda540b68660
Also, here's the expected output - I got it from pasting the above options file in the web version of https://export.highcharts.com/
But it works, like I said before, in about 20% of the cases.
"asyncRendering": true,
"resources": {
"files": "resources.js"
}
(resources.js === test.js)
Ah, my bad! highexp.done()
should be called before creating the chart. My code above doesn't make sense.
I have tried something like this (pre-load images):
function checkImages() {
if (Array.prototype.filter.call(document.images, function(img) { return !img.complete }).length === 0) {
highexp.done();
} else {
setTimeout(checkImages, 0);
}
}
function loadImages() {
var img = document.createElement('img');
img.src = 'https://dots.dataontouchdev.com/images/weather/yr_weather_symbols/svg/22n.svg';
img.style.position = 'absolute';
img.style.top = '-50px';
img.style.height = '40px';
img.style.width = '40px';
document.body.appendChild(img);
}
loadImages();
setTimeout(checkImages, 0);
Tested 10x with your config - works fine. Could you check it and let me know the results?
@pawelfus Your solution in the web version works, thank you! But when I try it in the terminal I get the following error:
phantom worker 1 unexpected data - TypeError: null is not an object (evaluating 'document.body.appendChild')
When I add throw new Error(document.body)
the result is:
phantom worker 1 unexpected data - Error: null
So, I guess document.body is null.
Hmm.. try then document.querySelector('body')
or document.querySelectorAll('body')[0]
? Perhaps we have different PhantomJS versions, hard to say.
@pawelfus I think I get the error because loadImages
is called before the document.body
is created...
neither document.querySelector('body')
nor document.querySelectorAll('body')[0]
works
That might be it, did you try putting the code into DOMContentLoaded
event's callback?
@pawelfus it worked! Thank you very much! The final solution looks like this:
function checkImages() {
if (document.body === null || Array.prototype.filter.call(document.images, function(img) { return !img.complete }).length === 0) {
highexp.done();
} else {
setTimeout(checkImages, 0);
}
}
function loadImages() {
var img = document.createElement('img');
img.src = 'https://dots.dataontouchdev.com/images/weather/yr_weather_symbols/svg/22n.svg';
img.style.position = 'absolute';
img.style.top = '-50px';
img.style.height = '40px';
img.style.width = '40px';
document.body.appendChild(img);
}
window.addEventListener('DOMContentLoaded', function(event) {
loadImages();
});
setTimeout(checkImages, 0);
Any official fix for this issue?
@pawelfus The solution above worked until 2 days ago. Now I'm getting error: callback, resources, and customCode have been disabled for this server
So, seems like we can't use the resources
parameter anymore.
@pawelfus I use the Highcharts export server (https://export.highcharts.com), so I can't utilize the --allowCodeExecution
option that they suggest. Anyway, the resources
parameter was utilized in order to overcome the bug that the library has - not loading the images. Now that we can't use this option anymore, is there any other way?
FYI @PaulDalek @cvasseng
None of these worked for me. Using chart to display to Discord using Node but no background Image tutorial I've used works 😢
Sorry for the late reply. This was a big deal in the PhantomJS version of the export server. It required using the asyncLoading
along with resources and triggering the highexp.done()
in order to wait for images. In the new Puppeteer version this is no longer required, as it waits for the images to load. All you need to do is to simply place the URL as a value of a specific option (in this case plotBackgroundImage
) and that’s it. Here is the result:
Like in the title. Node export server is not able to process neither .jpg nor base64 images.
Reproduction steps
I use highcharts-export-server --infile test.json In test.json file I have this config like this:
jsFiddle with above config: https://jsfiddle.net/BlackLabel/2tvcdqrs
highcharts-export-server v2.0.16 node v10.15.1