diff --git a/nezha-fronted/src/components/chart/chart/chartStat.vue b/nezha-fronted/src/components/chart/chart/chartStat.vue index 3f061271f..329a14207 100644 --- a/nezha-fronted/src/components/chart/chart/chartStat.vue +++ b/nezha-fronted/src/components/chart/chart/chartStat.vue @@ -13,7 +13,7 @@ 'chart-cursor-pointer':(dataLink.length || chartInfo.datasource === 'metrics' || chartInfo.datasource === 'logs') }" :style="{ - background:item.mapping ? item.mapping.color.bac : (statData.length===1 ? '' : colorList[index]), + background:item.backgroundColor, height:item.height+'px', width:item.width + 'px', }" @@ -21,9 +21,9 @@
@@ -170,14 +170,12 @@ export default { if (this.isNoData) { return } - this.getLayout().then(layout => { - this.renderStat(layout) - if (this.chartInfo.param.sparklineMode && this.chartInfo.param.sparklineMode !== 'none') { - this.$nextTick(() => { - this.drawChart() - }) - } - }) + this.renderStat() + if (this.chartInfo.param.sparklineMode && this.chartInfo.param.sparklineMode !== 'none') { + this.$nextTick(() => { + this.drawChart() + }) + } }) }, initStatData (chartInfo, originalDatas) { @@ -266,54 +264,54 @@ export default { resolve() }) }, - getLayout () { + calculateGridDimensions (parentWidth, parentHeight, numberOfChildren) { + const vertical = this.calculateSizeOfChild(parentWidth, parentHeight, numberOfChildren) + const horizontal = this.calculateSizeOfChild(parentHeight, parentWidth, numberOfChildren) + const square = Math.max(vertical, horizontal) + let xCount = Math.floor(parentWidth / square) + const yCount = Math.ceil(numberOfChildren / xCount) + + // after yCount update xCount to make split between rows more even + xCount = Math.ceil(numberOfChildren / yCount) + + const itemsOnLastRow = xCount - (xCount * yCount - numberOfChildren) + const widthOnLastRow = parentWidth / itemsOnLastRow + + return { + width: parentWidth / xCount, + height: parentHeight / yCount, + widthOnLastRow, + xCount, + yCount + } + }, + calculateSizeOfChild (parentWidth, parentHeight, numberOfChildren) { + const parts = Math.ceil(Math.sqrt((numberOfChildren * parentWidth) / parentHeight)) + if (Math.floor((parts * parentHeight) / parentWidth) * parts < numberOfChildren) { + return parentHeight / Math.ceil((parts * parentHeight) / parentWidth) + } + return parentWidth / parts + }, + renderStat () { try { this.boxWidth = this.$refs['chart-stat-box'].offsetWidth - 3 * this.boxPadding this.boxHeight = this.$refs['chart-stat-box'].offsetHeight - 3 * this.boxPadding } catch (error) {} - return new Promise(resolve => { - let rateMax = 0 - let col = 0 - let row = 0 - for (let i = 1; i <= this.statData.length; i++) { - const cols = Math.ceil(this.statData.length / i) - const w = this.boxWidth / i - const h = this.boxHeight / cols - const rate = w > h ? h / w : w / h - if (rate > rateMax) { - rateMax = rate - col = cols - row = i - } - } - if (this.statData.length) { - while (col * row >= this.statData.length) { // 避免出现空白 - row-- - } - } - row++ - if (col === 1 || row === 1) { // 行 或 列有一个为1时 需要调换位置 - const temp = col - col = row - row = temp - } - resolve({ col, row }) - }) - }, - renderStat (layout) { - const width = this.boxWidth / layout.col - const height = this.boxHeight / layout.row - const integer = Math.floor(this.statData.length / layout.col) - const remainder = this.statData.length % layout.col - const specialIndex = integer * layout.col - const specialWidth = this.boxWidth / remainder + + const grid = this.calculateGridDimensions(this.boxWidth, this.boxHeight, this.statData.length) + let xGrid = 0 + let yGrid = 0 + this.statData.forEach((item, index) => { - item.height = height - if (remainder && index >= specialIndex) { - item.width = specialWidth - } else { - item.width = width + const isLastRow = yGrid === grid.yCount - 1 + item.width = isLastRow ? grid.widthOnLastRow : grid.width + item.height = grid.height + xGrid++ + if (xGrid === grid.xCount) { + xGrid = 0 + yGrid++ } + let display = '' if (item.mapping) { display = this.handleDisplay(item.mapping.display, { ...item.label, value: item.showValue }) @@ -367,6 +365,9 @@ export default { item.titleFontSize = titleFontSize item.valueFontSize = valueFontSize + // 设置图表颜色和字体颜色 + this.setColor(item, index) + if (item.valueFontSize > 36) { item.comparisonFont = 16 } else if (item.valueFontSize > 24) { @@ -377,12 +378,24 @@ export default { }) this.isInit = false }, - + setColor (data, index) { + const colorMode = lodash.get(this.chartInfo, 'param.colorMode', 'value') + if (colorMode == 'value') { + data.textColor = this.colorList[index] + } else if (colorMode === 'background') { + data.backgroundColor = this.colorList[index] + } + if (data.mapping) { + data.textColor = data.mapping.color.text + data.backgroundColor = data.mapping.color.bac + } + }, + // 计算字体大小 calculateFontSize (text, width, height, maxSize, lineHeight = 1.2) { const el = this.$refs['temp-dom'] el.innerText = text const elWidth = el.offsetWidth - const fontSizeBasedOnWidth = (width / (elWidth + 2)) * 14 + const fontSizeBasedOnWidth = (width / elWidth) * 14 const fontSizeBasedOnHeight = height / lineHeight const optimalSize = Math.min(fontSizeBasedOnHeight, fontSizeBasedOnWidth) @@ -399,7 +412,7 @@ export default { const color = item.mapping ? item.mapping.color.bac : this.colorList[index] const lineColor = tinycolor(color).brighten(40).toRgbString() let areaColor = 'rgba(255,255,255,0.4)' - if (this.statData.length === 1 && !item.mapping) { + if (!item.backgroundColor) { areaColor = tinycolor(color).setAlpha(0.2).toRgbString() } @@ -427,14 +440,11 @@ export default { this.statTimer = null } this.statTimer = setTimeout(() => { - this.getLayout().then(layout => { - this.renderStat(layout) - - this.$nextTick(() => { - for (const key in this.sparkline) { - this.sparkline[key].resize() - } - }) + this.renderStat() + this.$nextTick(() => { + for (const key in this.sparkline) { + this.sparkline[key].resize() + } }) }, 100) }, @@ -513,7 +523,7 @@ export default { minHeight = 24 break } - return this.chartInfo.param.comparison && this.chartInfo.param.comparison !== 'none' && item.height > minHeight && item.width > minWidth + return (this.chartInfo.param.comparison && this.chartInfo.param.comparison !== 'none') && (item.height > minHeight && item.width > minWidth) }, toolboxPosition (e) { const windowWidth = window.innerWidth// 窗口宽度 diff --git a/nezha-fronted/src/components/common/bottomBox/tabs/notebookTab.vue b/nezha-fronted/src/components/common/bottomBox/tabs/notebookTab.vue index 232aa04ad..068ae42a6 100644 --- a/nezha-fronted/src/components/common/bottomBox/tabs/notebookTab.vue +++ b/nezha-fronted/src/components/common/bottomBox/tabs/notebookTab.vue @@ -189,6 +189,7 @@ export default { if (!this.obj.id) { // 新增 this.$post('visual/notebook', params).then(response => { if (response.code === 200) { + bus.$emit('notebookSave', { id: response.data.id, ...params }) this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) this.$emit('getTableData') this.$store.commit('setNotebookEdit', false) @@ -200,6 +201,7 @@ export default { params.id = this.obj.id this.$put('visual/notebook', params).then(response => { if (response.code === 200) { + bus.$emit('notebookSave', params) this.$message({ duration: 1000, type: 'success', message: this.$t('tip.saveSuccess') }) this.$emit('getTableData') this.$store.commit('setNotebookEdit', false) @@ -357,8 +359,7 @@ export default { tooltip: { mode: 'all', sort: 'none' - }, - option: undefined + } } break case 'stat': @@ -391,6 +392,7 @@ export default { }, sparklineMode: 'line', comparison: 'none', + colorMode: 'value', dataLink: [] } break @@ -515,6 +517,9 @@ export default { this.snapshotVisible = true }, downloadJson () { + if (!this.obj.id) { + return this.$message.error(this.$t('NOTEBOOK_ID_ISNULL')) + } const params = { format: 3, ids: this.obj.id diff --git a/nezha-fronted/src/components/common/rightBox/chart/chartConfig.vue b/nezha-fronted/src/components/common/rightBox/chart/chartConfig.vue index 1da98c76b..517533b56 100644 --- a/nezha-fronted/src/components/common/rightBox/chart/chartConfig.vue +++ b/nezha-fronted/src/components/common/rightBox/chart/chartConfig.vue @@ -414,9 +414,6 @@ > -
- -
+ + + + + + +
@@ -1470,10 +1480,6 @@ export default { case 'bubble': case 'rank': case 'funnel': - if (type === 'stat') { - if (!this.chartConfig.param.sparklineMode) { this.chartConfig.param.sparklineMode = 'line' } - if (!this.chartConfig.param.comparison) { this.chartConfig.param.comparison = 'none' } - } if (this.oldType === 'stat' || this.oldType === 'gauge' || this.oldType === 'sankey' || this.oldType === 'hexagon' || this.oldType === 'bubble' || this.oldType === 'rank' || this.oldType === 'funnel') { break } @@ -1500,6 +1506,7 @@ export default { }, sparklineMode: 'line', comparison: 'none', + colorMode: 'value', dataLink: this.chartConfig.param.dataLink } break diff --git a/nezha-fronted/src/components/common/rightBox/chart/chartRightBox.vue b/nezha-fronted/src/components/common/rightBox/chart/chartRightBox.vue index 3f6181ea5..c0106a6ad 100644 --- a/nezha-fronted/src/components/common/rightBox/chart/chartRightBox.vue +++ b/nezha-fronted/src/components/common/rightBox/chart/chartRightBox.vue @@ -258,6 +258,7 @@ export default { if (!this.isStat(params.type)) { delete params.param.sparklineMode delete params.param.comparison + delete params.param.colorMode } if (!params.x && !params.y && this.from === 'endpointQuery') { // endpointQuery 新增 放在最后 params.x = 0 @@ -527,6 +528,7 @@ export default { varValue: '', result: 'show' }, + colorMode: 'value', dataLink: [] } } @@ -727,8 +729,9 @@ export default { } } if (obj.type === 'stat') { - if (!obj.param.sparklineMode) { obj.param.sparklineMode = 'none' } + if (!obj.param.sparklineMode) { obj.param.sparklineMode = 'line' } if (!obj.param.comparison) { obj.param.comparison = 'none' } + if (!obj.param.colorMode) { obj.param.colorMode = 'value' } } if (obj.type == 'text' && !obj.param.editorType) { obj.param.editorType = 'richText' diff --git a/nezha-fronted/src/components/common/rightBox/chart/systemChartConfig.vue b/nezha-fronted/src/components/common/rightBox/chart/systemChartConfig.vue index 080ffd3dd..0a73ced8a 100644 --- a/nezha-fronted/src/components/common/rightBox/chart/systemChartConfig.vue +++ b/nezha-fronted/src/components/common/rightBox/chart/systemChartConfig.vue @@ -270,6 +270,19 @@ :placeholder="'Default 2'" show-word-limit v-model="chartConfig.param.decimals"/> + + + + + + +
@@ -1128,6 +1141,7 @@ export default { varValue: '', result: 'show' }, + colorMode: 'value', dataLink: this.chartConfig.param.dataLink } break diff --git a/nezha-fronted/src/components/page/notebook/notebook.vue b/nezha-fronted/src/components/page/notebook/notebook.vue index 0b2a35c4a..9804d5169 100644 --- a/nezha-fronted/src/components/page/notebook/notebook.vue +++ b/nezha-fronted/src/components/page/notebook/notebook.vue @@ -205,6 +205,13 @@ export default { } }, methods: { + notebookSave (data) { + if (this.detailType === 'list') { + this.$refs.dataList.showBottomBox('notebookTab', data) + } else { + this.detailViewRightObj = this.$lodash.cloneDeep(data) + } + }, add () { this.$store.commit('setNotebookEdit', true) const username = localStorage.getItem('nz-username') @@ -281,6 +288,10 @@ export default { this.initQueryFromPath(searchKeys) }, mounted () { + bus.$on('notebookSave', this.notebookSave) + }, + beforeDestroy () { + bus.$off('notebookSave', this.notebookSave) } }