Charts, Barcode & QR
This page covers two browser widgets you can drop into a custom Desk page or dialog: charts via frappe.Chart, and the camera-based barcode and QR scanner via frappe.ui.Scanner.
Charts
frappe.Chart is the Frappe Charts library, exposed on the global frappe object. Create one by passing a target element (a selector or DOM node) and a config object.
let chart = new frappe.Chart("#chart", {
title: __("Tasks by Status"),
type: "bar", // bar, line, pie, percentage, donut, heatmap
height: 300,
data: {
labels: ["Open", "In Progress", "Completed"],
datasets: [{ name: __("Tasks"), values: [12, 5, 30] }],
},
colors: ["#7cd6fd", "#743ee2", "#5e64ff"],
});
The data object holds labels (the x-axis) and datasets (one or more series of values). After creating the chart, update it without rebuilding:
chart.update({
labels: ["Open", "In Progress", "Completed"],
datasets: [{ name: __("Tasks"), values: [8, 9, 33] }],
});
chart.addDataPoint(__("Cancelled"), [2]); // append a point
chart.removeDataPoint(0); // remove the first point
You usually fetch the numbers from the server first, then feed them in. See Server Calls.
let rows = await frappe.xcall("myapp.api.task_counts");
new frappe.Chart("#chart", {
type: "pie",
data: {
labels: rows.map((r) => r.status),
datasets: [{ values: rows.map((r) => r.count) }],
},
});
Live charts
frappe.ui.RealtimeChart extends the chart and updates it from a realtime socket event.
new frappe.ui.RealtimeChart(element, event_name, max_label_points, data);
element: selector or DOM node to render into.event_name: the realtime event to listen on for new data.max_label_points: maximum number of points to keep on the x-axis. The chart drops the oldest point once it is full. Defaults to 8.data: the same config object you pass tofrappe.Chart, includingdata.datasets. The initial values array must not be longer thanmax_label_points.
let chart = new frappe.ui.RealtimeChart("#live", "task_update", 8, {
title: __("Tasks per minute"),
type: "line",
height: 250,
data: {
labels: ["t0"],
datasets: [{ name: __("Tasks"), values: [0] }],
},
});
chart.start_updating();
Methods:
start_updating(): listen onevent_nameand append each payload to the chart.stop_updating(): stop listening on that event.update_chart(label, points): append a point by hand.labelis the new x-axis label andpointsis the array of values, one per dataset.
Publish events from the server with frappe.publish_realtime. The payload must carry a label and a points array, with one value per dataset on the chart. See Realtime for more.
frappe.publish_realtime("task_update", {"label": "t1", "points": [10]})
Barcode and QR scanner
frappe.ui.Scanner opens the device camera and reads barcodes and QR codes. Set dialog: true to show it in a modal, and pass an on_scan callback. The callback receives the decoded result; the text is at result.result.text.
new frappe.ui.Scanner({
dialog: true,
multiple: false,
on_scan(result) {
if (result && result.result && result.result.text) {
let code = result.result.text;
frappe.show_alert(__("Scanned: {0}", [code]));
}
},
});
Options:
dialog: set true to open the scanner in a modal. Without it, passcontainer(a selector or element) to render the camera inline.multiple: set true to keep scanning after each read. The default stops after the first code.on_scan(result): called with each decoded result.
// inline, scanning many codes into a list
let codes = [];
let scanner = new frappe.ui.Scanner({
container: "#scan-area",
multiple: true,
on_scan(result) {
codes.push(result.result.text);
},
});
// inline mode does not auto-start; call scan() to begin
scanner.scan();
Any Data field with the scan option turned on already shows a scan button that uses this same scanner and writes the result into the field, so you do not need to wire it up by hand for that case.
Drawing barcodes
To render (not read) a barcode, use a field with the Barcode fieldtype. The control draws an SVG barcode from the field value automatically, so set the value and the image follows.