Vue中D3柱状图无法显示,报TypeError错误求助代码排查
排查D3柱状图报错及修复方案
嘿,我来帮你搞定这个D3柱状图的问题!你遇到的TypeError: Cannot read prototype '0'of undefined报错,主要是代码里几个关键的语法和属性引用错误导致的,咱们一步步来修正:
问题点分析
- 错误的柱子宽度计算:你用了
xScale.rangeRound()-this.rectPadding,但rangeRound()返回的是一个包含两个边界值的数组(比如[0, 440]),直接用数组减数字会触发类型错误,这就是你看到报错的核心原因。正确的做法是用xScale.bandwidth()获取每个柱子的基础带宽,再减去内边距。 - 属性名拼写错误:代码里写了
this.height,但你在data中定义的高度属性是h,应该改成this.h,否则会读取到undefined,导致后续高度计算出错。 - 缺失坐标轴渲染:虽然这不是当前报错的原因,但你只定义了x轴和y轴,却没有把它们添加到SVG中,最终图表会看不到坐标轴,建议补上这部分逻辑。
修复后的完整代码
<template> <div> <div id='chart'></div> </div> </template> <script> import * as d3 from 'd3' export default { name: 'priceChart', data() { return { price_open: 0, price_min: 1, price_max: 2, price_close: 3, w: 500, h: 400, paddingLeft: 30, paddingRight: 30, paddingTop: 20, paddingBottom: 20, volumeData:[10,20,30,40,33,24,12,5] } }, methods: { createSvg() { const svg = d3.select('#chart') .append('svg') .attr('width', this.w) .attr('height', this.h); let xScale = d3.scaleBand() .domain(d3.range(this.volumeData.length)) .rangeRound([0, this.w - this.paddingLeft - this.paddingRight]) .padding(0.1); // 自带的间距控制,比手动算padding更方便 let yScale = d3.scaleLinear() .domain([0, d3.max(this.volumeData)]) .range([this.h - this.paddingTop - this.paddingBottom, 0]) let xAxis = d3.axisBottom(xScale); let yAxis = d3.axisLeft(yScale); // 添加x轴到SVG svg.append("g") .attr("transform", `translate(${this.paddingLeft}, ${this.h - this.paddingBottom})`) .call(xAxis); // 添加y轴到SVG svg.append("g") .attr("transform", `translate(${this.paddingLeft}, ${this.paddingTop})`) .call(yAxis); let rectPadding = 4; let rects = svg.selectAll('.MyRect') .data(this.volumeData) .enter() .append('rect') .attr('class', 'MyRect') .attr('transform', `translate(${this.paddingLeft}, ${this.paddingTop})`) .attr('x', (d, i) => xScale(i)) .attr('y', (d) => yScale(d)) // 修正宽度计算:用bandwidth减去padding .attr('width', xScale.bandwidth() - rectPadding) // 修正height属性引用,用this.h代替this.height .attr('height', d => this.h - this.paddingTop - this.paddingBottom - yScale(d)) .attr('fill','red') } }, mounted() { this.createSvg(); } } </script>
额外优化建议
- 给
xScale加的.padding(0.1)是D3 scaleBand自带的间距控制方式,比手动计算rectPadding更直观,你可以根据需求调整这个值。 - 柱子的x坐标直接用
xScale(i)就可以了,不需要额外除以2,因为scaleBand已经帮你分配好了每个柱子的起始位置。
内容的提问来源于stack exchange,提问作者Sylvia
相关产品推荐
相关产品推荐

