blob: c3b883a1a1d93b103f7c12cc28526de119f7228a [file] [log] [blame]
<template>
<div>
<div slot='header' class='clearfix text-base'>
{{$t('data')}}
</div>
<div ref='table' id='table-panel' class='overflow-auto absolute bottom-4 top-14 left-5 right-5 border'>
</div>
</div>
</template>
<script lang='ts'>
import Handsontable from 'handsontable';
import {defineComponent} from 'vue';
import * as _ from 'lodash';
import * as Color from 'color';
const headerLength = 2;
export type ChartData = string[][];
function colorRenderer(instance, td, row, col, prop, value) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
if (col === 0 || value === '' || !value) {
return td;
}
try {
Color(value);
td.innerHTML = `<div style="width: 14px; height: 14px; display: inline-block; margin-right: 5px; margin-top: 5px; border-radius: 50%; background-color:${value}"></div><div style="display: inline-block; position: relative; top: -2px;">${value}</div>`;
}
catch (e) {
console.error(e);
}
return td;
}
export default defineComponent({
name: 'BTable',
props: {
},
data() {
return {
tableData: [
['', 'blueberry', 'kiwi', 'banana', 'watermelon']
// @ts-ignore:
.map(name => name ? this.$i18n.t(name) : ''),
// @ts-ignore:
[this.$i18n.t('color'), '', '', '', ''],
['2017', '13', '11', '12', '14'],
['2018', '20', '44', '34', '39'],
['2019', '62', '75', '58', '63'],
['2020', '98', '81', '78', '93'],
['2021', '139', '98', '88', '143']
],
table: null,
debouncedTableChange: null
}
},
mounted() {
this.insertEmptyCells();
this.table = new Handsontable(this.$refs.table as Element, {
data: this.tableData,
rowHeaders: true,
colHeaders: true,
filters: true,
dropdownMenu: true,
cell: [{
row: 0,
col: 0,
readOnly: true
}, {
row: 1,
col: 0,
readOnly: true,
data: 'Color'
}],
cells: function (row, col) {
if (row === 1) {
return {
renderer: colorRenderer
};
}
else {
return {};
}
}
});
this.table.updateSettings({
afterChange: () => {
console.log('after')
this.debouncedTableChange();
}
});
this.debouncedTableChange = _.debounce(() => {
this.$emit('afterChange', this.getChartData());
}, 500);
this.$emit('afterChange', this.getChartData());
},
unmounted() {
this.debouncedTableChange.cancel();
},
methods: {
getChartData(): ChartData {
let columns = 0;
const firstRow = this.tableData[0];
for (let i = 1; i < firstRow.length; ++i) {
if (!firstRow[i] || !firstRow[i].trim()) {
columns = i;
break;
}
}
let rows = headerLength;
for (let i = headerLength; i < this.tableData.length; ++i) {
if (!this.tableData[i] || !this.tableData[i][0] || !this.tableData[i][0]) {
rows = i;
break;
}
}
return this.tableData.slice(0, rows)
.map(row => row.slice(0, columns));
},
insertEmptyCells() {
for (let i = 0; i < this.tableData.length; ++i) {
for (let j = this.tableData[i].length; j < 50; ++j) {
this.tableData[i].push('');
}
}
for (let i = this.tableData.length; i < 100; ++i) {
const row = [];
for (let j = 0; j < 50; ++j) {
row.push('');
}
this.tableData.push(row);
}
},
trimColumns(rowData: (string | number)[]) {
for (let i = rowData.length - 1; i > 0; --i) {
if (rowData[i] && rowData[i] !== '') {
return rowData.slice(1, i + 1);
}
}
return [];
},
trimRows() {
const data = this.tableData;
if (data.length <= headerLength) {
return [];
}
for (let i = data.length - 1; i >= headerLength; --i) {
let isEmpty = true;
for (let j = 1; j < data[i].length; ++j) {
if (data[i][j] && data[i][j] !== '') {
isEmpty = false;
break;
}
}
if (!isEmpty) {
return data.slice(headerLength, i + 1);
}
}
return [];
},
getYData() {
if (this.tableData.length <= headerLength) {
return [];
}
return this.trimColumns(this.tableData[0]);
},
getSeriesData(id: number) {
if (this.tableData.length <= id + headerLength) {
return [];
}
return this.trimColumns(this.tableData[id + headerLength]);
},
getDataName(id: number) {
if (this.tableData.length <= id + headerLength) {
return '';
}
else {
return this.tableData[id + headerLength][0];
}
}
}
})
</script>
<style scoped>
@layer utilities {
}
</style>