Javascript 使 Array 中的新元素出现在 arr.push 之后的不同索引中(而不是预期的 arr.length 索引中)
Javascript makes new Element in Array appear in different index after arr.push (not in arr.length index as expected)
我有一个名为任务的数组。
我在那里存储了许多任务。
示例:
[
{
"id": "2",
"taskName": "dswrs",
"startDate": "1969-12-31T23:00:00.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:55.000Z",
"categorie": "Processing"
},
{
"id": "1",
"taskName": "A",
"startDate": "1969-12-31T23:00:30.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:25.000Z",
"categorie": "Processing"
}
]
在这里你已经可以看到我的问题了。我在带有 id:1 的元素之后添加了带有 id:2 的元素(带有 tasks.push(...)
)
所以我希望它按以下顺序排列:
[
{
"id": "1",
"taskName": "A",
"startDate": "1969-12-31T23:00:30.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:25.000Z",
"categorie": "Processing"
},
{
"id": "2",
"taskName": "dswrs",
"startDate": "1969-12-31T23:00:00.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:55.000Z",
"categorie": "Processing"
}
]
只有当新添加的元素比已经存在的元素多 lower startDate
时,才会出现此问题。
问题必须出在我的 D3.js 代码中,我用它在甘特图中显示数据。我希望它在 gantt.redraw
函数中,因为我在将新数据添加到我的任务数组后直接调用它,但我找不到问题所在。
/* global d3 */
d3.gantt = function () {
var initTimeDomain = function (tasks) {
console.log(tasks);
if (timeDomainMode === FIT_TIME_DOMAIN_MODE) {
if (tasks === undefined || tasks.length < 1) {
timeDomainStart = new Date(0);
timeDomainEnd = new Date(10 ** 5);
return;
}
var tasksOrder = tasks;
tasksOrder.sort(function (a, b) {
return a.endDate - b.endDate;
});
timeDomainEnd = tasksOrder[tasksOrder.length - 1].endDate;
tasksOrder.sort(function (a, b) {
return a.startDate - b.startDate;
});
timeDomainStart = tasksOrder[0].startDate;
}
};
function gantt (tasks) {
initTimeDomain();
initAxis();
var svg = d3.select('svg')
.attr('class', 'chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('class', 'gantt-chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
svg.selectAll('.chart')
.data(tasks, keyFunction).enter()
.append('rect')
.attr('rx', 5)
.attr('ry', 5)
.attr('class', function (d) {
if (taskCategorie[d.categorie] == null) { return 'bar-killed'; }
return taskCategorie[d.categorie];
})
.attr('y', 0)
.attr('transform', rectTransform)
// ----.attr('height', function (d) { return y.rangeBand(); })
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + (height - margin.top - margin.bottom) + ')')
.transition()
.call(xAxis);
svg.append('g').attr('class', 'y axis').transition().call(yAxis);
return gantt;
};
gantt.redraw = function (tasks) {
console.log("TASKS IN REDRAW: ")
console.log(tasks);
initTimeDomain(tasks);
initAxis();
var svg = d3.select('svg');
var ganttChartGroup = svg.select('.gantt-chart');
var rect = ganttChartGroup.selectAll('rect').data(tasks, keyFunction);
var div = d3.select('body').append('div')
.attr('class', 'tooltip-donut')
.style('opacity', 0);
rect.enter()
.insert('rect', ':first-child')
.on('mouseover', function (d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '.85');
// Makes the new div appear on hover:
div.transition()
.duration(50)
.style('opacity', 1);
div.html(['Taskname: ' + i.taskName, 'Start: ' + i.startDate.toLocaleTimeString(), 'Ende: ' + i.endDate.toLocaleTimeString()].join('<br/>'))
.style('left', (d.pageX + 10) + 'px')
.style('top', (d.pageY - 15) + 'px');
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '1');
div.transition()
.duration('50')
.style('opacity', 0);
})
.attr('rx', 5)
.attr('ry', 5)
.attr('class', function (d) {
if (taskCategorie[d.categorie] == null) { return 'bar-killed'; }
return taskCategorie[d.categorie];
})
.transition()
.attr('y', 0)
.attr('transform', rectTransform)
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
rect.transition()
.attr('transform', rectTransform)
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
rect.exit().remove();
svg.select('.x').transition().call(xAxis);
svg.select('.y').transition().call(yAxis);
console.log("TASKS NACH REDRAW: ")
console.log(tasks);
return gantt;
};
gantt.margin = function (value) {
if (!arguments.length)
return margin;
margin = value;
return gantt;
};
gantt.timeDomain = function (value) {
if (!arguments.length)
return [timeDomainStart, timeDomainEnd];
timeDomainStart = +value[0], timeDomainEnd = +value[1];
return gantt;
};
return gantt;
};
问题出在initTimeDomain
方法中。
您正在使用 var tasksOrder = tasks;
创建对 tasks 数组的新引用,然后按日期对 tasksOrder
进行排序。
这里的问题是 Javascript 对象和数组是引用,这意味着 tasksOrder
和 tasks
指向同一个数组。
说起来简单,修改一个也会修改另一个
如果你不想要这个,你需要创建一个真实的副本,像这样:
var tasksOrder = tasks.slice();
我有一个名为任务的数组。 我在那里存储了许多任务。 示例:
[
{
"id": "2",
"taskName": "dswrs",
"startDate": "1969-12-31T23:00:00.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:55.000Z",
"categorie": "Processing"
},
{
"id": "1",
"taskName": "A",
"startDate": "1969-12-31T23:00:30.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:25.000Z",
"categorie": "Processing"
}
]
在这里你已经可以看到我的问题了。我在带有 id:1 的元素之后添加了带有 id:2 的元素(带有 tasks.push(...)
)
所以我希望它按以下顺序排列:
[
{
"id": "1",
"taskName": "A",
"startDate": "1969-12-31T23:00:30.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:25.000Z",
"categorie": "Processing"
},
{
"id": "2",
"taskName": "dswrs",
"startDate": "1969-12-31T23:00:00.000Z",
"endDate": "1969-12-31T23:00:55.000Z",
"duration": "1969-12-31T23:00:55.000Z",
"categorie": "Processing"
}
]
只有当新添加的元素比已经存在的元素多 lower startDate
时,才会出现此问题。
问题必须出在我的 D3.js 代码中,我用它在甘特图中显示数据。我希望它在 gantt.redraw
函数中,因为我在将新数据添加到我的任务数组后直接调用它,但我找不到问题所在。
/* global d3 */
d3.gantt = function () {
var initTimeDomain = function (tasks) {
console.log(tasks);
if (timeDomainMode === FIT_TIME_DOMAIN_MODE) {
if (tasks === undefined || tasks.length < 1) {
timeDomainStart = new Date(0);
timeDomainEnd = new Date(10 ** 5);
return;
}
var tasksOrder = tasks;
tasksOrder.sort(function (a, b) {
return a.endDate - b.endDate;
});
timeDomainEnd = tasksOrder[tasksOrder.length - 1].endDate;
tasksOrder.sort(function (a, b) {
return a.startDate - b.startDate;
});
timeDomainStart = tasksOrder[0].startDate;
}
};
function gantt (tasks) {
initTimeDomain();
initAxis();
var svg = d3.select('svg')
.attr('class', 'chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('class', 'gantt-chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
svg.selectAll('.chart')
.data(tasks, keyFunction).enter()
.append('rect')
.attr('rx', 5)
.attr('ry', 5)
.attr('class', function (d) {
if (taskCategorie[d.categorie] == null) { return 'bar-killed'; }
return taskCategorie[d.categorie];
})
.attr('y', 0)
.attr('transform', rectTransform)
// ----.attr('height', function (d) { return y.rangeBand(); })
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + (height - margin.top - margin.bottom) + ')')
.transition()
.call(xAxis);
svg.append('g').attr('class', 'y axis').transition().call(yAxis);
return gantt;
};
gantt.redraw = function (tasks) {
console.log("TASKS IN REDRAW: ")
console.log(tasks);
initTimeDomain(tasks);
initAxis();
var svg = d3.select('svg');
var ganttChartGroup = svg.select('.gantt-chart');
var rect = ganttChartGroup.selectAll('rect').data(tasks, keyFunction);
var div = d3.select('body').append('div')
.attr('class', 'tooltip-donut')
.style('opacity', 0);
rect.enter()
.insert('rect', ':first-child')
.on('mouseover', function (d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '.85');
// Makes the new div appear on hover:
div.transition()
.duration(50)
.style('opacity', 1);
div.html(['Taskname: ' + i.taskName, 'Start: ' + i.startDate.toLocaleTimeString(), 'Ende: ' + i.endDate.toLocaleTimeString()].join('<br/>'))
.style('left', (d.pageX + 10) + 'px')
.style('top', (d.pageY - 15) + 'px');
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration('50')
.attr('opacity', '1');
div.transition()
.duration('50')
.style('opacity', 0);
})
.attr('rx', 5)
.attr('ry', 5)
.attr('class', function (d) {
if (taskCategorie[d.categorie] == null) { return 'bar-killed'; }
return taskCategorie[d.categorie];
})
.transition()
.attr('y', 0)
.attr('transform', rectTransform)
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
rect.transition()
.attr('transform', rectTransform)
.attr('height', function (d) { return y.bandwidth(); })
.attr('width', function (d) {
return (x(d.endDate) - x(d.startDate));
});
rect.exit().remove();
svg.select('.x').transition().call(xAxis);
svg.select('.y').transition().call(yAxis);
console.log("TASKS NACH REDRAW: ")
console.log(tasks);
return gantt;
};
gantt.margin = function (value) {
if (!arguments.length)
return margin;
margin = value;
return gantt;
};
gantt.timeDomain = function (value) {
if (!arguments.length)
return [timeDomainStart, timeDomainEnd];
timeDomainStart = +value[0], timeDomainEnd = +value[1];
return gantt;
};
return gantt;
};
问题出在initTimeDomain
方法中。
您正在使用 var tasksOrder = tasks;
创建对 tasks 数组的新引用,然后按日期对 tasksOrder
进行排序。
这里的问题是 Javascript 对象和数组是引用,这意味着 tasksOrder
和 tasks
指向同一个数组。
说起来简单,修改一个也会修改另一个
如果你不想要这个,你需要创建一个真实的副本,像这样:
var tasksOrder = tasks.slice();