apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.48k stars 19.62k forks source link

xAxis.nameGap and yAxis.nameGap should be set automatically given grid.containLabel #9265

Open jbadilla opened 6 years ago

jbadilla commented 6 years ago

xAxis.nameGap and yAxis.nameGap should be set automatically given grid.containLabel; this would provide the user with an easy way to display his/her axis name in a way that it doesn't visually interfere with the axis labels

One-line summary [问题简述]

Version & Environment [版本及环境]

Expected behaviour [期望结果]

When containLabel is selected, and a name for the xAxis or the yAxis has been specified, these should always fit on the graph's rendering, taking into account the 'rotate' property of the axis labels.

ECharts option [ECharts配置项]

if:

option = {
    grid.containLabel = true
    xAxis.axisLabel.rotate: someValue
    yAxis.axisLabel.rotate: someValue
}

then:

option = {
    grid.containLabel : true
    xAxis.axisLabel.rotate: someValue
    yAxis.axisLabel.rotate: someValue
    xAxis.nameGap : auto //should be set automatically
    yAxis.nameGap :  auto //should be set automatically
}

Other comments [其他信息]

deqingli commented 6 years ago

sorry, I don't quite understand what you mean, can you show me the ECharts option and the effect picture you want.

jbadilla commented 6 years ago

Certainly! I have included the option in the original post.

Explanation: I would like for the x-axis and y-axis names to be set based on the 'rotate' value of the axisLabel property inside xAxis and yAxis.

Justification: This is because sometimes the yAxis or xAxis labels overlaps with the yAxis or xAxis name. This is visually unpleasant, and it should be a standard feature that it automatically sets xAxis.nameGap and yAxis.nameGap so that it is not being overlapped by the axis labels.

How it should look:

screen shot 2018-10-24 at 9 05 38 am

Ovilia commented 6 years ago

Do you mean that you want to rotate the axis name or where do you want to place it? Sorry I didn't quite follow.

jbadilla commented 6 years ago

Here is how echarts behaves by default:

screen shot 2018-10-26 at 11 25 19 am

Here's how it should behave:

screen shot 2018-10-26 at 11 27 43 am

This has to be done by setting the xAxis.nameGap property to something reasonable

100pah commented 6 years ago

Currenly containLabel only considered axis labels, but not consider axis name.

@jbadilla

This axis lable is visually unpleasant because the default nameGap is 0.

Another issue #9286 gave a related situation that the axis name might overflow the rendering area.

To make the layout wisely, I think two enhancements can be taken into accout (and the two enhancement might be independent with each other in implementation):

(A) Enhanse the layout calculation of axis name: adjust it based on axis label and viewport.

Keep the current behaviors of nameLocation and nameGap, and add a new option nameLocationAdjust (or some likely name), which enable axis name to be auto adjusted to avoid interfering with axis labels and overflow the viewport, following the strategy below:

Procedure X: Layout axis name by the given nameLoation and nameGap, and then adjust it to avoid interfering with axis labels. Finally the relative location of axis name with axis line get. Detailedly, in this case, nameGap is not the gap with axis line any more, but actually is the gap with the bounding rect of both axis line and axis labels.

Procedure X will be executed twices if containLabel is set, the same as current implementation:

  1. The first execution is before the "coordinate system update stage", based on the estinamed axis label layout.
  2. The second execution is on the "cartesian rendering stage", based on the accrate axis label layout.

Procedure Y: Ajust the axis name to avoid overflowing the viewport (if it makes the axis name interfere with axis labels again, leave them there). Notice the overflow also need to be taken into account when nameLocation is start or end, like #9286 issued, which enables that when two cartesian exists axes align with each other without dynamic axis names overflow.

Procedure Y is only be executed in the "cartesian rendering stage", after Procedure X executed.

(B) Enhanse the cartesian rect determine calculation when containLabel

Currently containLabel has considdered axis label (and rotation). We should make it take into account the located axis name also, whatever the (A) is implemented or not.

But the logic looks not neat, a little complecated :(

What do you think @pissang

sunzy0212 commented 5 years ago

Currently, is there any workaround?

jbadilla commented 5 years ago

The workaround was offered in @100pah 's answer.

That being said, the 'nameGap' property is – in my opinion – flawed, because the property should not really exist. Rather, the 'nameGap' should be calculated internally, taking into account the length of the 'xAxis.axisLabels' and 'yAxis.axisLabels', as well as the 'rotate' property, which says how much labels should be rotated.

Any ideas?

sunzy0212 commented 5 years ago

@jbadilla Thanks for answers, but how can I get yAxis.axisLabels? Is there any api?

jbadilla commented 5 years ago

Hi @sunzy0212 ! Sorry I hadn't answered in a while; I've been neglecting this issue in my code, and have implemented a messy (albeit temporarily) solution so I could move on.

You should already have access to your categorical labels outside of echarts (e.g. in the data you use to build the chart). alternatively, you can use the echartsInstance object getOption function: https://ecomfe.github.io/echarts-doc/public/en/api.html#echartsInstance.getOption

Like @100pah says, the problem is not only the axis labels but also the viewport.

I will spend some time on this today

jbadilla commented 5 years ago

@100pah @pissang any news? do you expect to push a fix for this anytime soon?

fxxjdedd commented 5 years ago

I have the same problem, most of the problems can be solved by calculating nameGap externally, but when yAxis is the category axis, and the categories are very large, echarts will perform display optimization according to interval: 'auto', but we have no way to get which labels will eventually be displayed, which can cause problems with our final nameGap calculations.

image

fxxjdedd commented 5 years ago

I have the same problem, most of the problems can be solved by calculating nameGap externally, but when yAxis is the category axis, and the categories are very large, echarts will perform display optimization according to interval: 'auto', but we have no way to get which labels will eventually be displayed, which can cause problems with our final nameGap calculations.

image

image

After reviewing the source code related to the axis, I finally found the way to get the viewLabels in the instance of echarts!

AaronKauffman commented 4 years ago

Hello I just came across this problem in a project I am working on and was wondering the progress for a solution to the nameGap issue?

AbhaysinghBhosale commented 4 years ago

Is there any fix/workaround for this issue? In my case if nameGap set with static value it overlap once yAxis data reaches to 4 digit. and yAxis name overlap over ticks

fxxjdedd commented 4 years ago

@AbhaysinghBhosale https://github.com/apache/incubator-echarts/issues/9265#issuecomment-536500226 use the axis.getViewLabel and calculate these labels's dom width, then you get a nameGap...

jojozg7 commented 2 years ago

After 3 years, this problem is still relevant. Is there still hope that it will be fixed?

Either nameGap is set too high and the text disappears to the left, or it is set too low and overlaps with the numbers on the Y-axis.

Would be great if you could fix this.

DavidMarquezF commented 2 years ago

Seems like proposed pull request will fix it. Any ideas if it will be merged at some point?

tripathiarpit commented 2 years ago

@pissang has this been fixed in the any version of Chart.js

Ovilia commented 2 years ago

Changed calculated label gap to be passed from top #16825

There is a PR #16825 under review.

winkyBrain commented 1 year ago

Any news?

0x1f57 commented 10 months ago

在echarts实例setOption后调用下述方法可暂时解决此问题

/**
 * 修复Y轴名称间隔问题(Y轴名称与Y轴刻度标签重叠问题)
 * @param {EChartsType} chartInstance
 */
export function fixYAxisNameGap(chartInstance) {
  const globalModel = chartInstance._api.getModel()
  const yAxisList = globalModel.option.yAxis

  const ctx = document.createElement('canvas').getContext('2d')
  const nameGapList = []
  // 兼容多Y轴
  yAxisList.forEach(({ nameTextStyle, axisLabel }, index) => {
    const fontSize = nameTextStyle?.fontSize ?? 12
    const fontFamily = nameTextStyle?.fontFamily ?? 'sans-serif'
    ctx.save()
    ctx.font = `${fontSize}px ${fontFamily}`
    const yAxis = globalModel.getComponent('yAxis', index)?.axis
    // 计算刻度标签文字最大宽度
    const labelMaxWidth = Math.max(...yAxis.getViewLabels().map(item => ctx.measureText(item.formattedLabel).width))
    const axisLabelMargin = axisLabel?.margin ?? 8
    nameGapList.push(labelMaxWidth + axisLabelMargin + 5)
    ctx.restore()
  })

  chartInstance.setOption({
    yAxis: nameGapList.map(nameGap => ({ nameGap }))
  })
}
gmuralidharreddy commented 9 months ago

Is above PR will resolve this issue? If yes when can we expect it’s going to live?