Since 4.x, I can no longer change the font size of charts in reports via editing stylesheets or selecting fonts. This leads to very dismal appearance on HiDPI displays. Seems like this is caused by migration to charts.js.
A screenshot in HiDPI would be useful -- which fonts are too small?
chris, the issue isn't so much the HiDPI, it's that the chartjs strings aren't stylable with CSS, it's all hard-coded javascript. E.g. from an export of an Asset Piechart: var chartjsoptions = { "type" : "pie", "data" : { "labels" : [ "Stocks - $3,988.28 (37.7%)", "Open Funds - $2,348.49 ( 23.6%)", "Bonds - $1,952.50 (14.4%)", "Closed Funds - $972.66 (6 .4%)", "Purchase - $603.98 (5.1%)", "Primary - $457.51 (3.8%)", "Other - $325.39 (9.0%)"], "datasets" : [ { "urls" : [ "gnc-report:id=21#", "gnc-report:id=22#", "gnc-report:id=23#" , "gnc-report:id=24#", "gnc-register:acct-guid=d5bd17d34367962e5ba29e9a457a1015# ", "gnc-report:id=25#", "gnc-report:id=20#"], "data" : [ 3851988.28, 2412348.49, 1473952.5, 657672.66, 517603.98, 3898 57.51, 924525.39], "label" : "Accounts", "backgroundColor" : [ "#FF4136", "#FF851B", "#FFDC00", "#2ECC40", "#0074 D9", "#001f3f", "#85144b"], "borderColor" : [ "#FF4136", "#FF851B", "#FFDC00", "#2ECC40", "#0074D9", "#001f3f", "#85144b"] }] }, "options" : { "maintainAspectRatio" : false, "chartArea" : { "backgroundColor" : "#fffdf6" }, "legend" : { "position" : "right", "reverse" : false, "labels" : { "fontColor" : "black" } }, "elements" : { "line" : { "tension" : 0 }, "point" : { "pointStyle" : false } }, "tooltips" : { "callbacks" : { "label" : false } }, "scales" : { "xAxes" : [ { "display" : false, "type" : "category", "distribution" : "series", "offset" : true, "gridLines" : { "display" : true, "lineWidth" : 1.5 }, "scaleLabel" : { "display" : true, "labelString" : "" }, "ticks" : { "fontSize" : 12, "maxRotation" : 30 } }, { "position" : "top", "ticks" : { "display" : false }, "gridLines" : { "display" : false, "drawTicks" : false } }], "yAxes" : [ { "stacked" : false, "display" : false, "gridLines" : { "display" : true, "lineWidth" : 1.5 }, "scaleLabel" : { "display" : 1.5, "labelString" : "" }, "ticks" : { "fontSize" : 10, "beginAtZero" : false } }, { "position" : "right", "ticks" : { "display" : false }, "gridLines" : { "display" : false, "drawTicks" : false } }] }, "title" : { "display" : true, "fontSize" : 16, "fontStyle" : "", "text" : [ "Assets", "Balance at 12/31/2019: $10,948.81"] } } };
Sure. I wanted to have an idea how bad things would look in HiDPI. I don't have a Retina display to test. Options to fix this are: 1) add options for fontSizes -- there are currently 3 different ones in use in html-chart - options in either General Preferences or from the Stylesheet. 2) add 1 option for fontSize multiplier (default 1) -- in General Pref or Stylesheet -- and we multiply fontsizes manually 3) add 1 option for built-in chartjs multiplier from https://www.chartjs.org/docs/latest/general/device-pixel-ratio.html although I do not know how it can/should/will look like.
It could be that MacOS using libwebkit1 doesn't support https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio properly therefore causing this bug.
(In reply to Christopher Lam from comment #4) > It could be that MacOS using libwebkit1 doesn't support > https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio > properly therefore causing this bug. That seems unlikely given that the reporter says they're using Linux.
(In reply to Christopher Lam from comment #3) > Sure. I wanted to have an idea how bad things would look in HiDPI. I don't > have a Retina display to test. Options to fix this are: You're narrowing the bug down too much. While the reporter complained that charts don't look good on his HiDPI display, the general bug is that charts can't be styled with the stylesheets and that it's a regression from 3.x. ChartJS does all of the drawing directly so the code needs to read the stylesheet and populate that JSON array I pasted into comment 2 with the appropriate styles. I suggest you pick (and document in the wiki) some names corresponding to the json hierarchy. Start with making it style-able with the experimental CSS stylesheet since that's the overall direction we want to go. Something like chart.title { font-family: "Times"; font-size: "20px"; } in the stylesheet should change the JSON to "title" : { "display" : true, "fontSize" : 20, "fontFamily" : "Times", "fontStyle" : "", "text" : [ "Assets", "Balance at 12/31/2019: $10,948.81"] } } Don't forget to include chart.default.
Created attachment 373871 [details] Example chart under HiDPI on Debian. I now attached the screenshot of an example chart. The legend texts are extremely small and difficult to read.
Created attachment 373872 [details] sample patch I think this type of patch would work. JS to copy CSS rules into chartjs options. Not tested completely.
^ patch is obviously very incomplete and incorrect; idea is to create CSS rules and copy them onto chartjsoptions object.
(In reply to Christopher Lam from comment #9) > ^ patch is obviously very incomplete and incorrect; idea is to create CSS > rules and copy them onto chartjsoptions object. I think you want to get the CSS rules from Window.GetComputedStyle() rather than assuming the first stylesheet on the list and it would be better to iterate over all of the css nodes, though parsing all of the possibilities is going to be tedious.
(In reply to John Ralls from comment #10) > (In reply to Christopher Lam from comment #9) > > ^ patch is obviously very incomplete and incorrect; idea is to create CSS > > rules and copy them onto chartjsoptions object. > > I think you want to get the CSS rules from Window.GetComputedStyle() rather > than assuming the first stylesheet on the list and it would be better to > iterate over all of the css nodes, though parsing all of the possibilities > is going to be tedious. I looked at this. It unfortunately requires that the HTML contains an element eg. a dummy <title id="mytitle"></title> that we want to query the resultant style. We can also enumerate all stylesheets in play and pick up the styles.
Iterating over all of the stylesheets and computing which one's value applies for a particular property is nontrivial. Much better to let the browser do it. Maybe the dummy elements wouldn't be so bad.
(In reply to John Ralls from comment #12) > Iterating over all of the stylesheets and computing which one's value > applies for a particular property is nontrivial. Much better to let the > browser do it. Maybe the dummy elements wouldn't be so bad. Not too bad: scans all stylesheets, apply chart.* selectors to JSON. Not working yet. If there's another stylesheets with chart.title the second one will overwrite first. for (let stylesheet of document.styleSheets) { for (let rule of stylesheet.cssRules) { switch (rule.selectorText) { case 'chart.title': if (rule.style.fontFamily != \"\") { chartjsoptions.options.title.fontFamily = rule.style.fontFamily; } if (rule.style.fontSize != \"\") { chartjsoptions.options.title.fontSize = parseInt (rule.style.fontSize); } break; case 'chart.axes': if (rule.style.fontSize != \"\") { chartjsoptions.options.scales.xAxes[0].ticks.fontSize = parseInt (rule.style.fontSize); chartjsoptions.options.scales.yAxes[0].ticks.fontSize = parseInt (rule.style.fontSize); } break; case 'chart.legend': chartjsoptions.options.legend.labels.fontSize = parseInt (rule.style.fontSize); break; default: break; } } }
> If there's another stylesheets with chart.title the second one will overwrite first. That's not the correct way to handle it. The stylesheets are ordered somehow (I don't know how) and the properties in the "higher" ones overwrite the properties in "lower" ones... but if a property is set in the lower one and *not* overwritten it's still in effect. Like I said, not trivial.
(In reply to John Ralls from comment #14) > > If there's another stylesheets with chart.title the second one will overwrite first. > > That's not the correct way to handle it. The stylesheets are ordered somehow > (I don't know how) and the properties in the "higher" ones overwrite the > properties in "lower" ones... but if a property is set in the lower one and > *not* overwritten it's still in effect. Like I said, not trivial. Agree this way wouldn't be exactly the same as browsers. But I felt it was an acceptable hack (!!). FWIW for now, the reports only ever use 1 stylesheet. If we want to create a dummy <title> then it'll increase complexity: javascript to create element, query the css, delete element. Moreover, to use "chart.title" "chart.labels" etc as CSS selector we'll need to use <chart class="title"/> <chart class="labels"/> and query the resulting style. This is another hack? Easier is to use report vs stylesheet vs global option for fontSize or Multiplier (!!) and html-chart (or stylesheet renderer) can set the correct multiplier. Easiest of all, is to figure out how to make libwebkit1&2 display HiDPI-appropriate fontSizes; but I don't have HiDPI to experiment with.
> Easiest of all, is to figure out how to make libwebkit1&2 display HiDPI-appropriate fontSizes; but I don't have HiDPI to experiment with. That's a too-narrow view of the bug. Besides, that part is clearly a Linux (and maybe Windows) bug: On macOS (webkit's home OS) it already works. Oh, bingo. The element to hang the css off of is <canvas>, created at https://github.com/Gnucash/gnucash/blob/maint/gnucash/report/html-chart.scm#L410 where it's wrapped in a <div>. > If we want to create a dummy <title> then it'll increase complexity: javascript to create element, query the css, delete element. Moreover, to use "chart.title" "chart.labels" etc as CSS selector we'll need to use <chart class="title"/> <chart class="labels"/> and query the resulting style. This is another hack? No, you just need <div id="chart"> <div id="title"/> <div id="legend"/> <div id="x-axis"/> <div id="y-axis"/> <div id="etc"/> </div> There's no requirement at all for *displaying* elements and if the elements don't display then you don't have to delete them.
Maybe OP can test export report confirm if fonts still tiny when opened in web browser?
When opened in a web browser, the fonts are normal.
(In reply to hong from comment #18) > When opened in a web browser, the fonts are normal. This would suggest libwebkit2 is not receiving HiDPI status from the environment?
I think yes, as I have reported in webkit's bug tracker: https://bugs.webkit.org/show_bug.cgi?id=215062 But I think the comments above have made a good point: This is not so much about HiDPI; User could change font size in Gnucash 3.x, but lost the ability to do so in 4.x.
Created attachment 373873 [details] don't set fontSize in options, copy from body selector into default fontSize Luckily for me Ubuntu still has v3.8. It seems the "Text cell" style is used as base for the html-chart. This corresponds to the "body" selector. Here's a better idea. @OP: This may not work on your libwebkit. For me it works ^_^
Candidate fix https://github.com/Gnucash/gnucash/pull/789 Copies font-style, font-size and font-family from stylesheets into chartjs. Works well for me. Unsure: GnuCash stylesheets describe font-size in points eg "24pt", but ChartJS wants pixels; I've implemented a 4/3 multiplier as described in https://en.wikipedia.org/wiki/Point_(typography)#Desktop_publishing_point in this PR.
(In reply to Christopher Lam from comment #22)> > Unsure: > GnuCash stylesheets describe font-size in points eg "24pt", but ChartJS > wants pixels; I've implemented a 4/3 multiplier as described in > https://en.wikipedia.org/wiki/Point_(typography)#Desktop_publishing_point in > this PR. Actually libwebkit does the pt -> px conversion automatically when running getComputedStyle, so, no multiplier is needed. I've updated the PR. If @jralls is happy with it, we can merge this weekend.
Merged in time for 4.2. Charts will copy style from "Title" and "Text cell" corresponding to html <h3> and <body>.
Thanks, Chris. I can confirm this is fixed.