| <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> |