From 24550714f33008249111712d3598773ba8ea39f7 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Sun, 16 Sep 2018 20:50:13 +0800 Subject: [PATCH] [html-chart] add html-chart.scm to access ChartJS This is very similar to (but not 100% drop-in replacement) jqplot. --- gnucash/report/report-system/CMakeLists.txt | 1 + gnucash/report/report-system/html-chart.scm | 489 ++++++++++++++++++ .../report/report-system/html-document.scm | 3 + .../report/report-system/report-system.scm | 23 + .../report/report-system/test/CMakeLists.txt | 1 + .../report-system/test/test-html-chart.scm | 111 ++++ po/POTFILES.in | 1 + 7 files changed, 629 insertions(+) create mode 100644 gnucash/report/report-system/html-chart.scm create mode 100644 gnucash/report/report-system/test/test-html-chart.scm diff --git a/gnucash/report/report-system/CMakeLists.txt b/gnucash/report/report-system/CMakeLists.txt index 3e3243c69b..1d69dc32e2 100644 --- a/gnucash/report/report-system/CMakeLists.txt +++ b/gnucash/report/report-system/CMakeLists.txt @@ -61,6 +61,7 @@ set (report_system_SCHEME_2b set (report_system_SCHEME_3 commodity-utilities.scm html-acct-table.scm + html-chart.scm html-barchart.scm html-document.scm html-fonts.scm diff --git a/gnucash/report/report-system/html-chart.scm b/gnucash/report/report-system/html-chart.scm new file mode 100644 index 0000000000..f94e736904 --- /dev/null +++ b/gnucash/report/report-system/html-chart.scm @@ -0,0 +1,489 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; html-chart.scm : generate HTML programmatically, with support +;; for simple style elements. +;; +;; Added dependency on guile-json to help construct options. Migrated +;; from obsolete jquery and jqplot to modern chartjs instead in 2018 +;; by Christopher Lam +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2 of +;; the License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, contact: +;; +;; Free Software Foundation Voice: +1-617-542-5942 +;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 +;; Boston, MA 02110-1301, USA gnu@gnu.org +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(use-modules (json builder)) ;for building JSON options + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; utility functions for nested list handling +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; nested-alist-set! parameters are +;; lst - a nested alist e.g. (list (cons 'key1 'val1) +;; (cons 'key2 (list (cons 'key2-sub1 'val2a)))) +;; path - a list of symbols or single-element list +;; e.g. '(key2 key2-sub1) +;; '(key2 key2-sub2 (0)) +;; '(key3 key3-sub1 key3-sub1-sub1) +;; newval - the cdr of the innermost cons cell specified by the path +;; +;; see test-html-chart.scm for usage examples +(define (nested-alist-set! lst path newval) + (define (path->nested-alist path newval) + (let innerloop ((path (reverse path)) + (result newval)) + (cond + ((null? path) + result) + ((and (pair? (car path)) (number? (caar path))) + (innerloop (cdr path) + (let ((v (make-vector (1+ (caar path))))) + (vector-set! v (caar path) result) + v))) + (else + (innerloop (cdr path) + (list (cons (car path) result))))))) + + (let loop ((nested-lst lst) (path path)) + (cond + ((or (null? nested-lst) (null? path)) + (throw "invalid state")) + ((and (pair? (car path)) (number? (caar path))) + (cond + ((>= (caar path) (vector-length nested-lst)) + (throw (format #f "high vector index ~s must be set earlier" + (caar path)))) + ((list? (vector-ref nested-lst (caar path))) + (loop (vector-ref nested-lst (caar path)) + (cdr path))) + (else + (vector-set! nested-lst + (caar path) + (path->nested-alist (cdr path) newval))))) + (else + (let ((kvp (assq (car path) nested-lst))) + (cond + ((not kvp) ; new branch. append to end of parent branch + (list-cdr-set! nested-lst + (1- (length nested-lst)) + (path->nested-alist path newval))) + ((null? (cdr path)) ; existing branch, last path. replace pair's cdr + (set-cdr! kvp newval)) + (else ; existing branch. traverse into next layer. + (loop (cdr kvp) (cdr path))))))))) + +(define (nested-alist-get lst path) + (let loop ((nested-lst lst) (path path)) + (cond + ((null? path) + nested-lst) + ((null? nested-lst) + (throw "invalid state. most likely the initial list is empty.")) + ((and (pair? (car path)) (number? (caar path))) + (cond + ((>= (caar path) (vector-length nested-lst)) + (throw (format #f "invalid path vector index ~s too high" + (caar path)))) + (else + (loop (vector-ref nested-lst (caar path)) + (cdr path))))) + (else + (let ((kvp (assq (car path) nested-lst))) + (cond + ((not kvp) + (throw (format #f "invalid path: ~s" path))) + (else + (loop (cdr kvp) (cdr path))))))))) + +;; helper for setting data - guile-json expects vectors to be +;; transformed into JSON arrays; convert list to vector. if not list, +;; leave alone. +(define (list-to-vec v) + (if (list? v) + (list->vector v) + v)) + +;; The html-chart specifies options and data to create a chart. The +;; old chart toolkits guppi and jqplot seemed to require restrictive +;; specific formats for the options and data, and modern toolkit +;; chartjs is more permissive. Nonetheless some of the restrictions +;; remain. + +;; At minimum the html-chart will require setting the following +;; fields: +;; type - one of 'bar 'line 'pie +;; width - pair +;; height - pair + +(define + (make-record-type "" + '(width + height + chart-options + currency-iso + currency-symbol + custom-x-axis-ticks? + custom-y-axis-ticks?))) + +(define gnc:html-chart? + (record-predicate )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; class +;; generate the form for an html chart. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define gnc:make-html-chart-internal + (record-constructor )) + +(define (gnc:make-html-chart) + (gnc:make-html-chart-internal + '(percent . 100) ;;width + '(percent . 100) ;;height + (list ;;chartjs options object + (cons 'type 'bar) + (cons 'data (list + (cons 'labels #()) + (cons 'datasets #()))) + (cons 'options (list + (cons 'maintainAspectRatio #f) + (cons 'chartArea (list + (cons 'backgroundColor "#fffdf6"))) + (cons 'legend (list + (cons 'position 'right) + (cons 'reverse #f) + (cons 'labels (list + (cons 'fontColor 'black))))) + + (cons 'elements (list + (cons 'line (list + (cons 'tension 0))) + (cons 'point (list + (cons 'pointStyle #f))))) + (cons 'tooltips (list + (cons 'callbacks (list + (cons 'label #f))))) + + (cons 'scales (list + (cons 'xAxes (vector + (list + (cons 'display #t) + (cons 'type 'category) + (cons 'distribution 'series) + (cons 'offset #t) + (cons 'gridLines (list + (cons 'display #t) + (cons 'lineWidth 1.5))) + (cons 'scaleLabel (list + (cons 'display #t) + (cons 'labelString ""))) + (cons 'ticks (list + (cons 'fontSize 12) + (cons 'maxRotation 30)))) + ;; the following another xAxis at the top + '((position . top) + (ticks . ((display . #f))) + (gridLines . ((display . #f) + (drawTicks . #f)))) + )) + (cons 'yAxes (vector + (list + (cons 'stacked #f) + (cons 'display #t) + (cons 'gridLines (list + (cons 'display #t) + (cons 'lineWidth 1.5))) + (cons 'scaleLabel (list + (cons 'display 1.5) + (cons 'labelString ""))) + (cons 'ticks (list + (cons 'fontSize 10) + (cons 'beginAtZero #f)))) + ;; the following another yAxis on the right + '((position . right) + (ticks . ((display . #f))) + (gridLines . ((display . #f) + (drawTicks . #f)))) + )))) + (cons 'title (list + (cons 'display #t) + (cons 'fontSize 16) + (cons 'fontStyle "") + (cons 'text "")))))) + "XXX" ;currency-iso + "\u00A4" ;currency-symbol + #t ;custom x-axis ticks? + #t ;custom y-axis ticks? + )) + +(define gnc:html-chart-width + (record-accessor 'width)) + +(define gnc:html-chart-set-width! + (record-modifier 'width)) + +(define gnc:html-chart-height + (record-accessor 'height)) + +(define gnc:html-chart-set-height! + (record-modifier 'height)) + +(define (gnc:html-chart-type chart) + (gnc:html-chart-get chart '(type))) + +(define (gnc:html-chart-set-type! chart type) + (gnc:html-chart-set! chart '(type) type)) + +(define (gnc:html-chart-title chart) + (gnc:html-chart-get chart '(options title text))) + +(define-public (gnc:html-chart-set-title! chart title) + (gnc:html-chart-set! chart '(options title text) title)) + +(define-public (gnc:html-chart-set-data-labels! chart labels) + (gnc:html-chart-set! chart '(data labels) labels)) + +(define-public (gnc:html-chart-set-axes-display! chart display?) + (gnc:html-chart-set! chart '(options scales xAxes (0) display) display?) + (gnc:html-chart-set! chart '(options scales yAxes (0) display) display?)) + +(export gnc:html-chart-add-data-series!) +;; e.g.: +;; (gnc:html-chart-add-data-series! chart "label" list-of-numbers color +;; 'fill #t +;; 'urls "gnc-report:id=13#") +;; +;; chart - html-chart object +;; "label" - data series label eg. "Income" +;; data - a list-of-numbers specifying series data +;; color - a string specifying series colour +;; +;; other keys may be specified, see ChartJS documentation +;; 'fill - fill bar, or fill under line? +;; 'borderWidth - line width +;; 'urls - either a string (same url for whole data series) +;; or a list-of-string (individual url for each data point) +;; see javascript onClick event handler how they are decoded +(define* (gnc:html-chart-add-data-series! chart label data color . rest) + (let loop ((rest rest) + (newseries (list + (cons 'data (list-to-vec data)) + (cons 'label label) + (cons 'backgroundColor (list-to-vec color)) + (cons 'borderColor (list-to-vec color))))) + (if (null? rest) + (gnc:html-chart-set! + chart '(data datasets) + (list->vector + (append (vector->list + (or (gnc:html-chart-get chart '(data datasets)) + #())) + (list newseries)))) + (loop (cddr rest) + (assq-set! newseries + (car rest) + (list-to-vec (cadr rest))))))) + +(define-public (gnc:html-chart-clear-data-series! chart) + (gnc:html-chart-set! chart '(data datasets) #())) + +(define-public (gnc:html-chart-set-x-axis-label! chart label) + (gnc:html-chart-set! chart '(options scales xAxes (0) scaleLabel labelString) label)) + +(define-public (gnc:html-chart-set-stacking?! chart stack?) + (gnc:html-chart-set! chart '(options scales xAxes (0) stacked) stack?) + (gnc:html-chart-set! chart '(options scales yAxes (0) stacked) stack?)) + +(define-public (gnc:html-chart-set-grid?! chart grid?) + (gnc:html-chart-set! chart '(options scales xAxes (0) gridLines display) grid?) + (gnc:html-chart-set! chart '(options scales yAxes (0) gridLines display) grid?)) + +(define-public (gnc:html-chart-set-y-axis-label! chart label) + (gnc:html-chart-set! chart '(options scales yAxes (0) scaleLabel labelString) label)) + +(define gnc:html-chart-get-options-internal + (record-accessor 'chart-options)) + +(define gnc:html-chart-set-options-internal! + (record-modifier 'chart-options)) + +(define (gnc:html-chart-get chart path) + (let ((options (gnc:html-chart-get-options-internal chart))) + (nested-alist-get options path))) + +(define (gnc:html-chart-set! chart path val) + (let ((options (gnc:html-chart-get-options-internal chart)) + (val-vec (list-to-vec val))) + (nested-alist-set! options path val-vec) + (gnc:html-chart-set-options-internal! chart options))) + +(define gnc:html-chart-currency-iso + (record-accessor 'currency-iso)) + +(define gnc:html-chart-set-currency-iso! + (record-modifier 'currency-iso)) + +(define gnc:html-chart-currency-symbol + (record-accessor 'currency-symbol)) + +(define gnc:html-chart-set-currency-symbol! + (record-modifier 'currency-symbol)) + +(define gnc:html-chart-custom-x-axis-ticks? + (record-accessor 'custom-x-axis-ticks?)) + +(define-public gnc:html-chart-set-custom-x-axis-ticks?! + (record-modifier 'custom-x-axis-ticks?)) + +(define gnc:html-chart-custom-y-axis-ticks? + (record-accessor 'custom-y-axis-ticks?)) + +(define-public gnc:html-chart-set-custom-y-axis-ticks?! + (record-modifier 'custom-y-axis-ticks?)) + +(define JS-Number-to-String " +// The following snippet from MDN +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString +var toLocaleStringSupportsOptions = (typeof Intl == 'object' && Intl && typeof Intl.NumberFormat == 'function'); + +// format a number e.g. 2.5 into monetary e.g. \"$2.50\" +function numformat(amount) { + if (toLocaleStringSupportsOptions) { + return amount.toLocaleString(undefined, {style:'currency', currency:curriso}); + } else { + return currsym + amount.toLocaleString(); + } +} +") + + +(define JS-setup " +function tooltipLabel(tooltipItem,data) { + var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || 'Other'; + var label = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + switch (typeof(label)) { + case 'number': + return datasetLabel + ': ' + numformat(label); + default: + return ''; + } +} + +function tooltipTitle(array,data) { + return chartjsoptions.data.labels[array[0].index]; } + +// draw the background color +Chart.pluginService.register({ + beforeDraw: function (chart, easing) { + if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) { + var ctx = chart.chart.ctx; + var chartArea = chart.chartArea; + ctx.save(); + ctx.fillStyle = chart.config.options.chartArea.backgroundColor; + ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + ctx.restore(); + } + } +}) + +document.getElementById(chartid).onclick = function(evt) { + var activepoints = myChart.getElementAtEvent(evt); + var anchor = document.getElementById(jumpid); + switch (activepoints.length) { + case 0: + anchor.href = ''; + anchor.textContent = ''; + anchor.style = 'display: none'; + break; + default: + var index = activepoints[0]['_index']; + var datasetIndex = activepoints[0]['_datasetIndex']; + var datasetURLs = myChart.data.datasets[datasetIndex].urls; + // console.log('index=',index,'datasetIndex=',datasetIndex); + anchor.style = 'position:absolute; top:' + (evt.clientY - 30) + 'px; left:' + (evt.clientX - 20) + 'px; display: block; padding: 5px; border-radius: 5px; background: #4E9CAF; text-align:center; color:white; '; + switch (typeof(datasetURLs)) { + case 'string': + anchor.href = datasetURLs; + anchor.textContent = loadstring; + break; + case 'object': + anchor.href = datasetURLs[index]; + anchor.textContent = loadstring; + break; + default: + anchor.href = ''; + anchor.textContent = ''; + anchor.style = 'display: none'; + } + } +}\n\n") + +(define (get-options-string chart) + (scm->json-string + (gnc:html-chart-get-options-internal chart) + #:pretty #t)) + +(define (gnc:html-chart-render chart doc) + + (define (size->str size) + (string-append + (number->string (cdr size)) + (case (car size) + ((pixels) "px") + ((percent) "%")))) + + (let* ((retval '()) + (push (lambda (l) (set! retval (cons l retval)))) + ;; Use a unique chart-id for each chart. This prevents charts + ;; clashing on multi-column reports + (id (random 99999999))) + + (push (format #f "\n" + (gnc-path-find-localized-html-file "chartjs/Chart.bundle.min.js"))) + + (push (format #f "
\n" + (size->str (gnc:html-chart-width chart)) + (size->str (gnc:html-chart-height chart)))) + (push (format #f "\n" id)) + (push (format #f "\n" id)) + (push "
\n") + (push (format #f "") + + retval)) diff --git a/gnucash/report/report-system/html-document.scm b/gnucash/report/report-system/html-document.scm index b0c3da5774..9b9b95b3fa 100644 --- a/gnucash/report/report-system/html-document.scm +++ b/gnucash/report/report-system/html-document.scm @@ -369,6 +369,9 @@ ((gnc:html-anytag? obj) (gnc:make-html-object-internal gnc:html-anytag-render obj)) + ((gnc:html-chart? obj) + (gnc:make-html-object-internal gnc:html-chart-render obj)) + ((gnc:html-table-cell? obj) (gnc:make-html-object-internal gnc:html-table-cell-render obj)) diff --git a/gnucash/report/report-system/report-system.scm b/gnucash/report/report-system/report-system.scm index 7d1561f570..06aa679e19 100644 --- a/gnucash/report/report-system/report-system.scm +++ b/gnucash/report/report-system/report-system.scm @@ -427,6 +427,7 @@ (export gnc:html-linechart-render linechart) (export gnc:html-linechart-set-line-width!) (export gnc:html-linechart-line-width) + ;; html-style-info.scm (export ) @@ -558,6 +559,27 @@ (export gnc-commodity-table) (export gnc:uniform-commodity?) +;; html-chart.scm + +(export gnc:html-chart?) +(export gnc:make-html-chart) +(export gnc:html-chart-data) +(export gnc:html-chart-set-data!) +(export gnc:html-chart-width) +(export gnc:html-chart-set-width!) +(export gnc:html-chart-height) +(export gnc:html-chart-set-height!) +(export gnc:html-chart-type) +(export gnc:html-chart-set-type!) +(export gnc:html-chart-title) +(export gnc:html-chart-get) +(export gnc:html-chart-set!) +(export gnc:html-chart-currency-iso) +(export gnc:html-chart-set-currency-iso!) +(export gnc:html-chart-currency-symbol) +(export gnc:html-chart-set-currency-symbol!) +(export gnc:html-chart-render) + ;; html-table.scm (export ) @@ -762,6 +784,7 @@ (load-from-path "commodity-utilities") +(load-from-path "html-chart") (load-from-path "html-barchart") (load-from-path "html-document") (load-from-path "html-piechart") diff --git a/gnucash/report/report-system/test/CMakeLists.txt b/gnucash/report/report-system/test/CMakeLists.txt index 7167a516fa..23ff7d9b3b 100644 --- a/gnucash/report/report-system/test/CMakeLists.txt +++ b/gnucash/report/report-system/test/CMakeLists.txt @@ -19,6 +19,7 @@ set (scm_test_report_system_with_srfi64_SOURCES test-report-utilities.scm test-html-utilities-srfi64.scm test-html-fonts.scm + test-html-chart.scm test-report-html.scm test-report-system.scm ) diff --git a/gnucash/report/report-system/test/test-html-chart.scm b/gnucash/report/report-system/test/test-html-chart.scm new file mode 100644 index 0000000000..4e8e82d7b1 --- /dev/null +++ b/gnucash/report/report-system/test/test-html-chart.scm @@ -0,0 +1,111 @@ +(use-modules (gnucash gnc-module)) + +(gnc:module-begin-syntax (gnc:module-load "gnucash/app-utils" 0)) +(gnc:module-begin-syntax (gnc:module-load "gnucash/report/report-system" 0)) + +(use-modules (srfi srfi-64)) +(use-modules (tests srfi64-extras)) +(use-modules (tests test-engine-extras)) +(use-modules (tests test-report-system-extras)) +(use-modules (gnucash report report-system)) + +(define (run-test) + (test-runner-factory gnc:test-runner) + (test-begin "test-html-chart.scm") + (test-html-chart) + (test-end "test-html-chart.scm")) + + +(define (test-html-chart) + + (let ((chart (gnc:make-html-chart))) + + (gnc:html-chart-add-data-series! chart "label" '(2 3 4) "red") + + ;; general setters and getters + (gnc:html-chart-set! chart '(data datasets (0) data) #(1 2 3)) + (test-equal "data setter & getter" + #(1 2 3) + (gnc:html-chart-get chart '(data datasets (0) data))) + + (gnc:html-chart-set! chart '(type) 'scatter) + (test-equal "type setter & getter" + 'scatter + (gnc:html-chart-get chart '(type))) + + ;; options setters and getters + ;; + ;; options are stored in a nested list of pairs, in which the car + ;; is a symbol, the cdr is either a value (bool/string/number) + ;; another list of pairs, or another simple list + + ;; (list (cons 'maintainAspectRatio #f) + ;; (cons 'chartArea (list (cons 'backgroundColor "white"))) + ;; (cons 'scales (list (cons 'xAxes (list + ;; (list (cons 'display #t) + ;; (cons 'gridlines (list (cons 'display #t) + ;; (cons 'lineWidth 1.5))) + ;; (cons 'ticks (list (cons 'fontSize 12))))))))) + + ;; traversal is accomplished as a list of symbols or numbers + ;; e.g. '(maintainAspectRatio), '(chartArea backgroundColor), + ;; '(scales xAxes (0) display). NOTE: xAxes specifies a number to + ;; identify the kth element in the list. this is required as per + ;; chartjs specification. + ;; + ;; syntax is: (gnc:html-chart-set! chart path newval) or + ;; (gnc:html-chart-get chart path) + + (gnc:html-chart-set! chart '(options maintainAspectRatio) 'abc) + (test-equal "root option setter & getter" + 'abc + (gnc:html-chart-get chart '(options maintainAspectRatio))) + + (gnc:html-chart-set! chart '(options legend position) 'de) + (test-equal "1st level option setter & getter" + 'de + (gnc:html-chart-get chart '(options legend position))) + + (test-error + "1st level option fails - cannot traverse through existing path" + 'invalid-path + (gnc:html-chart-set! chart '(options legend position invalid) 'de)) + + (test-equal "deep nested new path - inexistent" + #f + (gnc:html-chart-get chart '(create new nested path))) + + (gnc:html-chart-set! chart '(create new nested path) 'newpath) + (test-equal "created deep nested new path" + 'newpath + (gnc:html-chart-get chart '(create new nested path))) + + (gnc:html-chart-set! chart '(create list-kth (4) nested path) 'k4th) + (test-equal "deep nested new path - created 4th list item" + 'k4th + (gnc:html-chart-get chart '(create list-kth (4) nested path))) + + (gnc:html-chart-set! chart '(create list-kth (1) nested path) 'k1th) + (test-equal "deep nested new path - created 1th list item" + 'k1th + (gnc:html-chart-get chart '(create list-kth (1) nested path))) + + (gnc:html-chart-set! chart '(create list-kth (0) nested path) 'k0th) + (test-equal "deep nested new path - created 0th list item" + 'k0th + (gnc:html-chart-get chart '(create list-kth (0) nested path))) + + (test-equal "deep nested new path - 4th list item intact" + 'k4th + (gnc:html-chart-get chart '(create list-kth (4) nested path))) + + (gnc:html-chart-set! chart '(create list-kth (3)) 'three) + (test-equal "deep nested new path - 3th list item is the last path" + 'three + (gnc:html-chart-get chart '(create list-kth (3)))) + + (test-error + "deep nested new path - cannot set 6th index" + 'error + (gnc:html-chart-set! chart '(create list-kth (6) nested path) 'k4th)) + )) diff --git a/po/POTFILES.in b/po/POTFILES.in index 0f4e85d158..146c2e99f4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -480,6 +480,7 @@ gnucash/report/report-system/gnc-report.c gnucash/report/report-system/html-acct-table.scm gnucash/report/report-system/html-anytag.scm gnucash/report/report-system/html-barchart.scm +gnucash/report/report-system/html-chart.scm gnucash/report/report-system/html-document.scm gnucash/report/report-system/html-fonts.scm gnucash/report/report-system/html-linechart.scm