javascriptvue.jsvuejs3echarts

How can I set width and height of a vue-echart? (not canvas width and height)


I'm using vue-echarts and I created following component:

<script setup lang="ts">
import { use } from 'echarts/core'
import { GaugeChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import VChart from 'vue-echarts'

use([GaugeChart, CanvasRenderer])

const option = {
  series: [
    {
      type: 'gauge',
      startAngle: 180,
      endAngle: 0,
      radius: '100%',
      detail: {
        width: '60%', // default 100
        lineHeight: 40, // default 30
        offsetCenter: [0, -12],
        formatter: (value) => `{value|${value}}`,
        rich: {
          value: { fontSize: 40 }
        }
      },
      data: [{ value: 58.2 }]
    }
  ]
}
</script>

<template>
  <VChart
    style="width: 600px; height: 400px"
    :option
  />
</template>

When I use the component, this is the result: enter image description here

As you can see the perimeter of the gauge chart is way smaller than its container (canvas). Since I want to use this component in other places, I don't want all of this white space. Is there a way to specify the exact width and height that the chart must take?

Edit #1

With some trial and error, I manged to reach this point:

enter image description here

Now the gauge chart looks exactly how I want it, the only issue is the extra bottom space which make it heigher than it really is. Since I want to use this component around (and align it), I can't use it with this extra bottom space. Is there a way to remove it without impacting the appearance it has right now?

Updated code:

<script setup lang="ts">
import { use } from 'echarts/core'
import { GaugeChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import VChart from 'vue-echarts'

use([GaugeChart, CanvasRenderer])

const option = {
  series: [
    {
      type: 'gauge',
      startAngle: 180,
      endAngle: 0,
      radius: '100%',
      detail: {
        offsetCenter: [0, -8],
        formatter: (value) => `{value|${value}}`,
        rich: {
          value: { fontSize: 24 }
        }
      },
      data: [{ value: 58.2 }]
    }
  ]
}
</script>

<template>
  <VChart
    style="width: 150px; height: 150px"
    :option
  />
</template>

Edit #2

Thanks to @rozsazoltan precious insights, I was able to reach my goal, full code below:

<script setup lang="ts">
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { GaugeChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'

const props = defineProps<{
  kpi: number
}>()

use([GaugeChart, CanvasRenderer])

const roundCap = true
const width = 12

const option = {
  series: [
    {
      type: 'gauge',
      center: ['50%', '62.5%'],
      radius: '100%',
      startAngle: 180,
      endAngle: 0,
      min: 0,
      max: 100,
      splitNumber: undefined,
      itemStyle: { color: '#58D9F9' },
      progress: {
        show: true,
        roundCap,
        width
      },
      pointer: undefined,
      axisLine: {
        roundCap,
        lineStyle: { width }
      },
      title: {
        offsetCenter: [0, 20],
        fontSize: 12
      },
      detail: {
        offsetCenter: [0, -8],
        valueAnimation: true,
        formatter: (value) => `{value|${value}}`,
        rich: {
          value: {
            fontSize: 20,
            fontWeight: 'bolder',
            color: 'black'
          }
        }
      },
      data: [
        {
          value: props.kpi,
          name: 'My Title'
        }
      ]
    }
  ]
}
</script>

<template>
  <VChart
    class="chart d-inline-block"
    :option
  />
</template>

<style scoped>
.chart {
  width: 105px;
  height: 105px;
}
</style>

Solution

  • TL;DR

    The width and height values provided to the canvas must be proportional to the chart's dimensions to fully occupy it without stretching.

    Reviewing the photos, you'll notice that regardless of the canvas size, the chart can be centered within it, but when zooming in on the chart, remaining empty spaces persist due to the improper canvas size.

    Another example: It's akin to trying to project a portrait photo onto a 1920x1080 (landscape) screen. There will always be empty space on the screen that the image cannot fill.




    Can use the options presented in the answer.

    original chart

    Since you're only using half of the gauge-type diagram, half of the space remains empty. Therefore, by setting series.center, we can center the diagram by using [50%, 75%] values. (The vertical 75% is derived from half of the empty space at 50% plus half of the remaining space.)

    {
      center: ["50%", "75%"],
      radius: "100%",
    }
    

    illustration to description --> [50%, 75%]

    Now we can zoom in on the diagram to cover the entire area.

    {
      center: ["50%", "75%"],
      radius: "150%", // +50%
    }
    

    illustration to description --> 150%

    It's now apparent that the original canvas size (600x400) doesn't have the appropriate aspect ratio for the diagram. We need to examine the aspect ratio of the diagram and resize the canvas accordingly.

    illustration to empty space --> 100px

    I've marked the maximum height of the diagram, leaving 100px of empty space above, which is unnecessary. So if I resize the canvas to 600x300, it will fit perfectly.

    <!-- -100px from height -->
    <VChart style="width: 600px; height: 300px;" />
    
    {
      center: ["50%", "75%"],
      radius: "150%",
    }
    

    set new height of canvas

    We can see that the empty space has decreased. However, as mentioned, the settings for series.center and series.radius in the diagram adjust according to the canvas height and width, so they need to be fine-tuned again for the new 300px height.

    Since the empty space has now halved (when height was 400px, empty space was 200px; now height is 400px-100px = 300px so empty space will just 200px-100px = 100px), I'll set the 75% to 100%: series.center: [50%, 100%]. Then, accordingly, I'll increase the diagram size not by 50% but by 100%, doubling it to series.radius: 200%.

    <VChart style="width: 600px; height: 300px;" />
    
    {
      center: ["50%", "100%"],
      radius: "200%",
    }
    

    result

    So, in short, this is how I would modify your source code:

    <script setup lang="ts">
    import { use } from 'echarts/core'
    import { GaugeChart } from 'echarts/charts'
    import { CanvasRenderer } from 'echarts/renderers'
    import VChart from 'vue-echarts'
    
    use([GaugeChart, CanvasRenderer])
    
    const option = {
      series: [
        {
          type: 'gauge',
          
          center: ["50%", "100%"], // set [50%, 100%] instead of [50%, 50%]
          radius: "200%", // set 200% instead of 100%
    
          // ...
        }
      ]
    }
    </script>
    
    <template>
      <!-- set 300px height instead of 400px -->
      <VChart
        style="width: 600px; height: 300px;"
        :option
      />
    </template>
    

    Example - codesandbox.io (It contains a bit more code since I used CSS to overlay red lines onto the screenshots.)

    Note: Your code didn't precisely depict the diagram in the image, but following the logic, you can adjust the sizing for your own diagram.

    And of course, you can fine-tune it by 1-2 pixels to leave a small margin. On my photo without this (margin) correction, perhaps the last 2 values: 0% and 100%, are just outside.




    Currently, the width ratio is 2:1 compared to the height. So, keeping the currently option settings, the width and height of the canvas can be adjusted in any way, and the diagram will fit the canvas.

    Of course, if the gauge outline or arc (or etc.) is different, then you'll need to recalculate it yourself.