mirror of
https://github.com/dataease/dataease.git
synced 2026-06-16 20:42:07 +08:00
fix(图表): 修复图表极值显示错位的问题
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g2": "^5.3.5",
|
||||
"@antv/g2": "^5.4.0",
|
||||
"@antv/l7": "^2.22.0",
|
||||
"@antv/l7plot": "^0.5.5",
|
||||
"@antv/s2": "^2.4.5",
|
||||
|
||||
@@ -90,7 +90,7 @@ export const extremumEvt = (
|
||||
// 这里获取 y 字段
|
||||
// 部分图表传过来的是options包含 children 的数组
|
||||
// 部分图表是children数组中的对象,line or bar
|
||||
const { y: yField } = options.encode
|
||||
const { y: yField } = options.encode ? options.encode : options.children[0].encode
|
||||
const chartData = options.children ? options.children : [options]
|
||||
// 遍历所有 series,为标签注入 HTML 和样式
|
||||
chartData
|
||||
@@ -119,35 +119,37 @@ export const extremumEvt = (
|
||||
pointSize = Math.max(pointSize, item.encode?.size || 0)
|
||||
})
|
||||
|
||||
const parentRect = parent?.getBoundingClientRect()
|
||||
// 渲染后调整极值标签位置,防止溢出
|
||||
newChart.on('afterrender', () => {
|
||||
document.querySelectorAll('.extremum-' + chart.container).forEach(item => {
|
||||
const setExtremumPosition = () => {
|
||||
document.querySelectorAll('.extremum-' + chart.container)?.forEach(item => {
|
||||
item.style.display = 'block'
|
||||
item?.parentElement?.parentElement
|
||||
const itemRect = item.getBoundingClientRect()
|
||||
const childNode = item.childNodes[1] as HTMLElement
|
||||
const itemParentRect = item.parentElement?.getBoundingClientRect()
|
||||
const spanElement = item.parentElement.querySelector('span' as string) as HTMLElement
|
||||
// 判断是否顶部溢出
|
||||
if (itemRect.top < parentRect.top) {
|
||||
item.style.transform = `translate(-50%) translateY(${pointSize / scale + 10}px)`
|
||||
childNode.style.cssText += 'transform: translateX(-50%) rotate(180deg); top: -5px;'
|
||||
const itemParentParentRect = item.parentElement?.parentElement?.getBoundingClientRect()
|
||||
// 顶部有足够空间
|
||||
if (itemParentRect.top - itemParentParentRect.top > itemParentRect.height) {
|
||||
item.style.transform = `translateY(-${itemRect.height + 5}px)`
|
||||
spanElement.style.cssText += 'transform: rotate(0deg);top: -6px;'
|
||||
} else {
|
||||
item.style.transform = `translateY(${pointSize / scale + 5 * 2}px)`
|
||||
spanElement.style.cssText += `transform: rotate(180deg);top: ${pointSize / scale + 5}px;`
|
||||
}
|
||||
// 判断是否右侧溢出
|
||||
if (itemRect.right > parentRect.right) {
|
||||
const currentLeft = parseFloat(window.getComputedStyle(item).left) || 0
|
||||
const newLeft = currentLeft - (itemRect.right - parentRect.right)
|
||||
item.style.left = `${newLeft}px`
|
||||
// childNode 反向偏移,保持始终指向在数据点上
|
||||
childNode.style.left = itemRect.width / 2 + Math.abs(newLeft) + 'px'
|
||||
}
|
||||
// 判断是否左侧溢出
|
||||
if (itemRect.left < parentRect.left) {
|
||||
const currentLeft = parseFloat(window.getComputedStyle(item).left) || 0
|
||||
const newLeft = currentLeft + (parentRect.left - itemRect.left)
|
||||
item.style.left = `${newLeft}px`
|
||||
// childNode 反向偏移,保持始终指向在数据点上
|
||||
childNode.style.left = itemRect.width / 2 - Math.abs(newLeft) + 'px'
|
||||
// 判断右侧溢出
|
||||
const overflowRight = itemParentRect.right - itemParentParentRect.right
|
||||
let newRight = itemRect.width / 2
|
||||
if (overflowRight > itemRect.width * 0.5) {
|
||||
newRight = overflowRight
|
||||
}
|
||||
item.style.right = newRight + 'px'
|
||||
})
|
||||
}
|
||||
newChart.on('afterchangesize', () => {
|
||||
setExtremumPosition()
|
||||
})
|
||||
newChart.on('afterrender', () => {
|
||||
setExtremumPosition()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -244,18 +246,16 @@ const extremumHtml = (chart, yField, isSeriesLabel) => {
|
||||
background: rgba(${color});
|
||||
">
|
||||
${textContent}
|
||||
<span style="
|
||||
</div>
|
||||
<span style="
|
||||
position: absolute;
|
||||
bottom: -4.8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: -6px;
|
||||
left: -4px;
|
||||
width: 0; height: 0;
|
||||
border-top: 5px solid rgba(${color});
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: 0;
|
||||
"></span>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '@/views/chart/components/js/panel/charts/g2/bar/common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { flow, hexColorToRGBA, hexToRgba, parseJson } from '@/views/chart/components/js/util'
|
||||
import { cloneDeep, isEmpty } from 'lodash-es'
|
||||
import { cloneDeep, defaultsDeep, isEmpty } from 'lodash-es'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import {
|
||||
getLineDash,
|
||||
@@ -83,8 +83,7 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
background: true
|
||||
}
|
||||
},
|
||||
transform: [{ type: 'dodgeX' } as Transform],
|
||||
data: []
|
||||
transform: [{ type: 'dodgeX' } as Transform]
|
||||
} as ViewSpec
|
||||
|
||||
async drawChart(drawOptions: G2DrawOptions<G2Column>): Promise<G2Column> {
|
||||
@@ -96,14 +95,11 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
const data = cloneDeep(drawOptions.chart.data?.data)
|
||||
const initOptions: ViewSpec = {
|
||||
type: 'view',
|
||||
data: {
|
||||
value: data
|
||||
},
|
||||
data: data,
|
||||
children: [
|
||||
{
|
||||
...this.intervalOptions,
|
||||
transform: [].concat(this.intervalOptions.transform),
|
||||
data
|
||||
transform: [].concat(this.intervalOptions.transform)
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -120,17 +116,6 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
scale,
|
||||
this.name === 'bar' || this.name === 'bar-group'
|
||||
)
|
||||
newChart.afterRender = (c?: any) => {
|
||||
extremumEvt(
|
||||
c,
|
||||
chart,
|
||||
c.options(),
|
||||
container,
|
||||
scale,
|
||||
this.name === 'bar' || this.name === 'bar-group'
|
||||
)
|
||||
c.render()
|
||||
}
|
||||
return newChart
|
||||
}
|
||||
|
||||
@@ -155,12 +140,9 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
const position = {
|
||||
position: l.position === 'middle' ? 'inside' : l.position,
|
||||
textAlign: 'center',
|
||||
dy: l.position === 'top' ? -10 : 0,
|
||||
dy: l.position === 'top' ? -15 : 0,
|
||||
dx: 0
|
||||
}
|
||||
const transform = {
|
||||
transform: [{ type: 'exceedAdjust' }, { type: 'overlapHide' }]
|
||||
}
|
||||
// 配置标签样式
|
||||
const newLabel = {
|
||||
text: 'value',
|
||||
@@ -195,8 +177,10 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
return ''
|
||||
}
|
||||
return valueFormatter(value, labelCfg.formatterCfg)
|
||||
},
|
||||
...(l.fullDisplay ? { transform: [{ type: 'exceedAdjust' }] } : transform)
|
||||
}
|
||||
}
|
||||
if (!l.fullDisplay) {
|
||||
newLabel.transform = [{ type: 'overlapHide' }]
|
||||
}
|
||||
return {
|
||||
...options,
|
||||
@@ -712,6 +696,29 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
}
|
||||
}
|
||||
|
||||
protected configSlider(chart: Chart, options: ViewSpec): ViewSpec {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
if (!functionCfg?.sliderShow) {
|
||||
return options
|
||||
}
|
||||
const lineMark = options.children[0]
|
||||
const sliderOpt = {
|
||||
slider: {
|
||||
x: {
|
||||
values: [functionCfg.sliderRange[0] / 100, functionCfg.sliderRange[1] / 100],
|
||||
style: {
|
||||
trackFill: functionCfg.sliderBg,
|
||||
selectionFill: functionCfg.sliderFillBg,
|
||||
handleLabelFill: functionCfg.sliderTextColor,
|
||||
sparklineLineStrokeOpacity: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
defaultsDeep(lineMark, sliderOpt)
|
||||
return options
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: ViewSpec): ViewSpec {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
@@ -722,7 +729,8 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
this.configXAxis,
|
||||
this.configYAxis,
|
||||
this.configAnalyse,
|
||||
this.configBarConditions
|
||||
this.configBarConditions,
|
||||
this.configSlider
|
||||
)(chart, options, {}, this)
|
||||
}
|
||||
|
||||
|
||||
@@ -97,10 +97,7 @@ export class Area extends G2ChartView {
|
||||
// 开始渲染
|
||||
newChart.options(options)
|
||||
newChart.on('point:click', action)
|
||||
newChart.afterRender = (c?: any) => {
|
||||
extremumEvt(c, chart, c.options(), container, scale, this.name === 'area')
|
||||
c.render()
|
||||
}
|
||||
extremumEvt(newChart, chart, options, container, scale)
|
||||
// configPlotTooltipEvent(chart, newChart)
|
||||
return newChart
|
||||
}
|
||||
@@ -258,9 +255,7 @@ export class Area extends G2ChartView {
|
||||
}
|
||||
return labelCfg.position === 'top' ? 'bottom' : 'top'
|
||||
},
|
||||
transform: labelAttr.fullDisplay
|
||||
? [{ type: 'exceedAdjust' }]
|
||||
: [{ type: 'exceedAdjust' }, { type: 'overlapHide' }],
|
||||
...(labelAttr.fullDisplay ? {} : { transform: [{ type: 'overlapHide' }] }),
|
||||
fontFamily: chart.fontFamily
|
||||
}
|
||||
]
|
||||
@@ -736,9 +731,7 @@ export class StackArea extends Area {
|
||||
textBaseline: () => {
|
||||
return labelAttr.position === 'top' ? 'bottom' : 'top'
|
||||
},
|
||||
transform: labelAttr.fullDisplay
|
||||
? [{ type: 'exceedAdjust' }]
|
||||
: [{ type: 'exceedAdjust' }, { type: 'overlapHide' }],
|
||||
...(labelAttr.fullDisplay ? {} : { transform: [{ type: 'overlapHide' }] }),
|
||||
fontFamily: chart.fontFamily
|
||||
}
|
||||
]
|
||||
|
||||
@@ -95,10 +95,7 @@ export class Line extends G2ChartView {
|
||||
const newChart = new G2Chart({ container })
|
||||
newChart.options(options)
|
||||
newChart.on('point:click', action)
|
||||
newChart.afterRender = (c?: any) => {
|
||||
extremumEvt(c, chart, c.options(), container, scale)
|
||||
c.render()
|
||||
}
|
||||
extremumEvt(newChart, chart, options, container, scale)
|
||||
// configPlotTooltipEvent(chart, newChart)
|
||||
return newChart
|
||||
}
|
||||
@@ -257,9 +254,7 @@ export class Line extends G2ChartView {
|
||||
}
|
||||
return labelCfg.position === 'top' ? 'bottom' : 'top'
|
||||
},
|
||||
transform: labelAttr.fullDisplay
|
||||
? [{ type: 'exceedAdjust' }]
|
||||
: [{ type: 'exceedAdjust' }, { type: 'overlapHide' }],
|
||||
...(labelAttr.fullDisplay ? {} : { transform: [{ type: 'overlapHide' }] }),
|
||||
fontFamily: chart.fontFamily
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user