我已经看到这类问题问了很多,但没有找到答案我找到了解决它。
我在这里创建了一个关于我的代码的简化版本的小提琴
https://jsfiddle.net/00m2cv84/4/
这里是一个ganttish对象的片段 - 最好看看小提琴虽然上下文
const ganttish = function (data) {
this.dataSet = data
this.fullWidth = +document.getElementById('chart').clientWidth
this.fullHeight = 700
this.pad = { top: 50, right: 50, bottom: 50, left: 50 }
this.h = this.fullHeight - this.pad.top - this.pad.bottom
this.w = this.fullWidth - this.pad.left - this.pad.right
this.svg = d3.select('#chart')
.append('svg')
.attr('width', this.fullWidth)
.attr('height', this.fullHeight)
}
ganttish.prototype = {
redraw (newDataSet) {
this.dataSet = newDataSet // this should overwrite the old data
this.draw()
},
draw () {
let y = d3.scaleBand()
.padding(0.1)
.range([0, this.h])
y.domain(this.dataSet.map(d => d.idea_id))
let x = d3.scaleTime().range([this.pad.left, this.w + this.pad.left])
x.domain([
d3.min(this.dataSet, d => new Date(Date.parse(d.start_date))),
d3.max(this.dataSet, d => new Date(Date.parse(d.end_date)))
])
let xAxis = d3.axisBottom(x).tickSize(-(this.h), 0, 0)
let yAxis = d3.axisLeft(y).tickSize(-(this.w), 0, 0)
let xA = this.svg.append('g')
.attr('transform', 'translate(0,' + this.h + ')')
.attr('class', 'x axis')
.call(xAxis)
let yA = this.svg.append('g')
.attr('transform', 'translate(' + this.pad.left + ', 0)')
.attr('class', 'y axis')
.call(yAxis)
let timeBlocks = this.svg.selectAll('.timeBlock')
.data(this.dataSet)
let tbGroup = timeBlocks
.enter()
.append('g')
tbGroup
.append('rect')
.attr('class', 'timeBlock')
.attr('rx', 5)
.attr('ry', 5)
.attr('x', d => x(new Date(Date.parse(d.start_date))))
.attr('y', d => y(d.idea_id))
.attr('width', d => parseInt(x(new Date(Date.parse(d.end_date))) - x(new Date(Date.parse(d.start_date)))))
.attr('height', d => y.bandwidth())
.style('fill', (d) => {
return d.color ? d.color : 'rgba(123, 173, 252, 0.7)'
})
.style('stroke', 'black')
.style('stroke-width', 1)
tbGroup
.append('text')
.attr('class', 'timeBlockText')
.attr('x', d => x(new Date(Date.parse(d.start_date))) + 10)
.attr('y', d => y(d.idea_id) + (y.bandwidth() / 2))
.attr('alignment-baseline', 'middle')
.attr('font-size', '1em')
.attr('color', 'black')
.text(d => d.name)
/**
I have literally tried exit().remove() on pretty much everything i could think of :(
this.svg.exit().remove()
timeBlocks.exit().remove()
this.svg.selectAll('.timeBlock').exit().remove()
this.svg.selectAll('.timeBlockText').exit().remove()
this.svg.select('.x').exit().remove()
this.svg.select('.y').exit().remove()
*/
}
旁注: 我有一个Vue js应用程序,我正在实现一个Gantt(ish)风格的水平条形图。在小提琴中,我通过创建一个Object来模拟Vue部分,然后在其上调用重绘方法,此模式模拟组件中的观察者在父数据更改时更新数据集。我面临的问题是一样的。
问题: 当我将数据更改为图表时,它不会更新我的图表或文本。然而,它确实将新轴添加到旧轴之上。
我知道我应该在任何.enter()上调用.exit()。remove(),以便在下一次数据推送时清除它们,但是在我尝试它的任何地方它都会失败。我可以通过在每次抽奖中创建一个新的svg来实现它,但我知道我将无法进行任何过渡 - 这似乎是一种非常糟糕的方法:)
什么是扭曲我的面条是如果我将额外的数据推送到新的数据对象,它会将其附加好,一次 - 然后再不会这样做。似乎一旦添加了数据数组中的元素X,它就不会再次更新。
https://jsfiddle.net/00m2cv84/5/
我知道this.dataSet正在更新,它似乎没有被D3接受
任何帮助都会非常感谢D3菜鸟:)
答案 0 :(得分:0)
您的问题是您没有正确处理数据连接。我强烈建议阅读Mike Bostock的一些例子,可能从Three Little Circles开始。总结一下:
通过调用.data()
创建的D3连接包含3个选项:
在您的代码中,您使用以下代码处理enter()
选项:
let tbGroup = timeBlocks
.enter()
.append('g')
问题是你没有处理任何其他选择。我这样做的方式是:
let join = this.svg.selectAll('.timeBlock').data(this.dataSet);
// Get rid of any old data
join.exit().remove();
// Create the container groups. Note that merge takes the "new" selection
// and merges it with the "update" selection. We'll see why in a minute
const newGroups = join.enter()
.append('g')
.merge(join);
// Create all the new DOM elements that we need
newGroups.append("rect").attr("class", "timeBlock");
newGroups.append('text').attr('class', 'timeBlockText');
// We need to set values for all the "new" items, but we also want to
// reflect any changes that have happened in the data. Because we used
// `merge()` previously, we can access all the "new" and "update" items
// and set their values together.
join.select(".timeBlock")
.attr('rx', 5)
.attr('ry', 5)
.attr('x', d => x(new Date(Date.parse(d.start_date))))
.attr('y', d => y(d.idea_id))
...
join.select(".timeBlockText")
.attr('x', d => x(new Date(Date.parse(d.start_date))) + 10)
.attr('y', d => y(d.idea_id) + (y.bandwidth() / 2))
.attr('alignment-baseline', 'middle')
.attr('font-size', '1em')
.attr('color', 'black')
.text(d => d.name)