You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

215 lines
9.0 KiB

/** @odoo-module **/
import { loadJS } from '@web/core/assets';
import { getColor } from "@web/core/colors/colors";
import { _t } from "@web/core/l10n/translation";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
const { Component, xml, onWillStart, useRef, onMounted } = owl
export class DynamicDashboardChart extends Component {
// Setup function of the class DynamicDashboardChart
setup() {
this.doAction = this.props.doAction.doAction;
this.chartRef = useRef("chart");
this.dialog = this.props.dialog;
onWillStart(async () => {
await loadJS("https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js")
await loadJS("https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js")
await loadJS("https://cdn.jsdelivr.net/npm/exceljs@4.4.0/dist/exceljs.min.js")
})
onMounted(()=> this.renderChart())
}
// Function to export the chart in pdf, image, xlsx and csv format
exportItem(ev){
ev.stopPropagation();
ev.preventDefault();
var type = $(ev.currentTarget).attr('data-type');
var canvas = $($($(ev.currentTarget)[0].offsetParent)[0].children[0].lastChild).find("#canvas")[0]
var dataTitle = $(canvas).attr('data-title')
var bgCanvas = document.createElement("canvas");
bgCanvas.width = canvas.width;
bgCanvas.height = canvas.height;
var bgCtx = bgCanvas.getContext("2d");
bgCtx.fillStyle = "white";
bgCtx.fillRect(0, 0, canvas.width, canvas.height);
bgCtx.drawImage(canvas, 0, 0);
var imgData = bgCanvas.toDataURL("image/png");
if (type === 'png') {
var downloadLink = document.createElement('a');
downloadLink.href = imgData;
downloadLink.download = `${dataTitle}.png`;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
if (type === 'pdf') {
var pdf = new jsPDF();
pdf.addImage(imgData, 'PNG', 0, 0);
pdf.save(`${dataTitle}.pdf`);
}
if (type === 'xlsx'){
var rows = [];
var items = $('.resize-drag');
for (let i = 0; i < items.length; i++) {
if ($(items[i]).attr('data-id') === $(ev.currentTarget).attr('data-id')) {
rows.push(this.props.widget.x_axis);
rows.push(this.props.widget.y_axis);
}
}
// Prepare the workbook
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('My Sheet');
for(let i = 0; i < rows.length; i++){
worksheet.addRow(rows[i]);
}
const image = workbook.addImage({
base64: imgData,
extension: 'png',
});
worksheet.addImage(image, {
tl: { col: 0, row: 4 },
ext: { width: canvas.width, height: canvas.height }
});
// Save workbook to a file
workbook.xlsx.writeBuffer()
.then((buffer) => {
// Create a Blob object from the buffer
let blob = new Blob([buffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.setAttribute("download", `${dataTitle}.xlsx`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
}
if (type === 'csv') {
var rows = [];
var items = $('.resize-drag')
for (let i = 0; i < items.length; i++) {
if ($(items[i]).attr('data-id') === $(ev.currentTarget).attr('data-id')) {
rows.push(this.props.widget.x_axis);
rows.push(this.props.widget.y_axis);
}
}
let csvContent = "data:text/csv;charset=utf-8,";
rows.forEach(function (rowArray) {
let row = rowArray.join(",");
csvContent += row + "\r\n";
});
var link = document.createElement("a");
link.setAttribute("href", encodeURI(csvContent));
link.setAttribute("download", `${dataTitle}.csv`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
// Function to get the configuration of the chart
async getConfiguration(ev){
ev.stopPropagation();
ev.preventDefault();
var id = this.props.widget.id
await this.doAction({
type: 'ir.actions.act_window',
res_model: 'dashboard.block',
res_id: id,
view_mode: 'form',
views: [[false, "form"]]
});
}
// Function to remove the chart
async removeTile(ev){
ev.stopPropagation();
ev.preventDefault();
this.dialog.add(ConfirmationDialog, {
title: _t("Delete Confirmation"),
body: _t("Are you sure you want to delete this item?"),
confirmLabel: _t("YES, I'M SURE"),
cancelLabel: _t("NO, GO BACK"),
confirm: async () => {
await this.props.orm.unlink("dashboard.block", [this.props.widget.id]);
location.reload();
},
cancel: () => {},
});
}
// Function to render the chart
renderChart(){
if (this.props.widget.graph_type){
const x_axis = this.props.widget.x_axis
const y_axis = this.props.widget.y_axis
const data = []
for (let i = 0; i < x_axis.length; i++) {
const value = { key: x_axis[i], value: y_axis[i] }
data.push(value);
}
new Chart(
this.chartRef.el,
{
type: this.props.widget.graph_type || 'bar',
data: {
labels: data.map(row => row.key),
datasets: [
{
label: this.props.widget.measured_field || 'Data',
data: data.map(row => row.value),
backgroundColor: data.map((_, index) => getColor(index)),
hoverOffset : 4
}
]
},
}
);
}
}
}
DynamicDashboardChart.template = xml`
<div class="resize-drag block card"
t-att-data-x="this.props.widget.data_x"
t-att-data-y="this.props.widget.data_y"
t-att-style="'height:'+this.props.widget.height+'; width:'+ this.props.widget.width+ '; transform: translate('+ this.props.widget.translate_x +', '+ this.props.widget.translate_y +');'"
t-att-data-id="this.props.widget.id">
<div class="card-body mt-1" id="in_ex_body_hide">
<div class="block_edit block_setting" t-on-click="(ev) => this.getConfiguration(ev)">
<i title="Configuration"
class="fa fa-pencil block_setting chart-edit"/>
</div>
<div class="block_edit block_image" data-type="png" t-on-click="(ev) => this.exportItem(ev)">
<i title="Save As Image"
class="bi bi-image block_image chart-image"/>
</div>
<div class="block_edit block_pdf" data-type="pdf" t-on-click="(ev) => this.exportItem(ev)">
<i title="Export to PDF"
class="bi bi-file-earmark-pdf block_pdf chart-pdf"/>
</div>
<div class="block_edit block_csv" t-att-data-id="this.props.widget.id" data-type="csv" t-on-click="(ev) => this.exportItem(ev)">
<i title="Export to CSV"
class="bi bi-filetype-csv block_csv chart-csv"/>
</div>
<div class="block_edit block_xlsx" t-att-data-id="this.props.widget.id" data-type="xlsx" t-on-click="(ev) => this.exportItem(ev)">
<i title="Export to XLSX"
class="fa fa-file-excel-o block_xlsx chart-xlsx"/>
</div>
<div class="block_edit block_delete" t-on-click="(ev) => this.removeTile(ev)">
<i title="Delete"
class="fa fa-times block_delete chart-setting"/>
</div>
<h3 class="chart_title">
<t t-esc="this.props.widget.name"/>
</h3>
<div class="row">
<div class="col-md-12 chart_canvas" id="chart_canvas"
t-att-data-id="this.props.widget.id">
<canvas id="canvas" t-ref="chart" t-att-data-title="this.props.widget.name"/>
</div>
</div>
</div>
</div>
`