javascript - 一个接一个的过渡圈
问题描述
我有以下html结构。
<div id = 'divTest'>
<div id = 'divSVG'>
</div>
<button id ='bStep' type="button">Step</button>
<button id = 'bRun' type="button">Entire run</button>
</div>
使用 D3,我在一个假想的正方形内创建了 10 个随机定位的圆,其左上角位于 (5, 5) 且长边为 10。
const n = 10; // number of circles
//Creating random circles inside a square whose l = 10
//The top left corner of the square is at (5, 5)
const x_ini = 5;
const y_ini = 5;
const x_length = 10;
const y_length = 10
const dataset = [];
for(let i = 0; i < n; i ++) {
const randomNumberX = Math.random()
const x = randomNumberX * x_length + x_ini;
const randomNumberY = Math.random()
const y = randomNumberY * y_length + y_ini;
const pair = [x, y];
dataset[i] = pair;
}
const svg = d3.select('#divSVG')
.append('svg')
.attr('width', 300)
.attr('height', 300);
const circles = svg.selectAll('.circleTest')
.data(dataset)
.enter()
.append('circle')
.attr('cx', d => d[0])
.attr('cy', d => d[1])
.attr('class', 'circleTest')
.attr('r', 1)
.attr('fill', 'black');
在 step 按钮中,我添加了一个函数,可以将一个圆圈移动到另一个虚构的圆圈,并更改它的类。
//Moves one circle to an imaginary square whose top left corner is at (100, 5)
d3.select('#bStep')
.on('click', () => {
const x_ini = 100;
const y_ini = 5;
const x_length = 10;
const y_length = 10;
const randomNumberX = Math.random()
const x = randomNumberX * x_length + x_ini;
const randomNumberY = Math.random()
const y = randomNumberY * y_length + y_ini;
const circle = d3.select('.circleTest')
.transition()
.duration(1000)
.attr('cx', x)
.attr('cy', y)
.attr('fill', 'red')
.attr('class', 'circleTest2')
});
我希望通过单击“整个运行”按钮,所有圆圈不会同时移动,而是根据一些输入数据一一转换。例如,基于“指令”向量,在第一次转换中只移动一个圆圈,然后移动三个圆圈,依此类推。我怎样才能做到这一点?
d3.select('#bRun')
.on('click', () => {
const instructions = [1, 3, 0, 2, 4, 1]
// Move all circles based on some input like 'instructions'
});
解决方案
这是一种基于不同数组执行这种转换的方法。
const instructions = [1, 3, 0, 2, 4, 1];
var pointer = 0;
function moveCircles () {
if(!instructions[pointer]) {
console.log('No circles to be transitioned');
setTimeout(function () { moveCircles(); }, 1000);
return ;
}
// Move all circles based on some input like 'instructions'
if(pointer > instructions.length-1) {
console.log("No more instructions.");
return ;
}
if(!d3.selectAll('circle.circleTest:not(.transitioned)').size()) {
console.log('No more circles to be transitioned');
return ;
}
// transition circles
var circles = d3.selectAll('circle.circleTest:not(.transitioned)')
.filter(function (d, i) {
return i < instructions[pointer];
});
circles.transition()
.duration(1000).on('end', function (d, i) {
if(i === circles.size()-1) {
pointer++;
moveCircles();
}
}).attr('cx', x)
.attr('cy', y)
.attr('fill', 'red')
.attr('class', 'transitioned');
}
d3.select('#bRun')
.on('click', () => {
moveCircles();
});
我正在分配一个过渡到已经过渡的圈子的类,您可以通过您选择的任何方式重置它。
解释:
- 指向指令数组的指针。
- 单击时,检查指针是否超出指令数组的范围,或者是否没有更多的圆圈要转换,或者指令[指针] === 0。
- 选择所有没有
transitioned
类的圈子,根据它们过滤instructions[pointer]
并转换它们。 - 在每个场景中增加指针。
- #2 和 #3 中的递归调用逻辑。
这是一个工作片段:
const n = 10; // number of circles
//Creating random circles inside a square whose l = 10
//The top left corner of the square is at (5, 5)
const x_ini = 5;
const y_ini = 5;
const x_length = 10;
const y_length = 10
const dataset = [];
for(let i = 0; i < n; i ++) {
const randomNumberX = Math.random()
const x = randomNumberX * x_length + x_ini;
const randomNumberY = Math.random()
const y = randomNumberY * y_length + y_ini;
const pair = [x, y];
dataset[i] = pair;
}
const svg = d3.select('#divSVG')
.append('svg')
.attr('width', 300)
.attr('height', 300);
const circles = svg.selectAll('.circleTest')
.data(dataset)
.enter()
.append('circle')
.attr('cx', d => d[0])
.attr('cy', d => d[1])
.attr('class', 'circleTest')
.attr('r', 1)
.attr('fill', 'black');
// transition co-ordinates computation
const x_ini_to = 100;
const y_ini_to = 5;
const randomNumberX = Math.random()
const x = randomNumberX * x_length + x_ini_to;
const randomNumberY = Math.random()
const y = randomNumberY * y_length + y_ini_to;
//Moves one circle to an imaginary square whose top left corner is at (100, 5)
d3.select('#bStep')
.on('click', () => {
const circle = d3.select('.circleTest')
.transition()
.duration(1000)
.attr('cx', x)
.attr('cy', y)
.attr('fill', 'red')
.attr('class', 'circleTest2')
});
const instructions = [1, 3, 0, 2, 4, 1];
var pointer = 0;
function moveCircles () {
if(!instructions[pointer]) {
pointer++;
console.log('No circles to be transitioned');
setTimeout(function () { moveCircles(); }, 1000);
return ;
}
// Move all circles based on some input like 'instructions'
if(pointer > instructions.length-1) {
console.log("No more instructions.");
return ;
}
if(!d3.selectAll('circle.circleTest:not(.transitioned)').size()) {
console.log('No more circles to be transitioned');
return ;
}
// transition circles
var circles = d3.selectAll('circle.circleTest:not(.transitioned)').filter(function (d, i) {
return i < instructions[pointer];
});
circles.transition()
.duration(1000).on('end', function (d, i) {
if(i === circles.size()-1) {
pointer++;
moveCircles();
}
}).attr('cx', x)
.attr('cy', y)
.attr('fill', 'red')
.attr('class', 'transitioned');
}
d3.select('#bRun')
.on('click', () => {
moveCircles();
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id = 'divTest'>
<div id = 'divSVG'>
</div>
<button id ='bStep' type="button">Step</button>
<button id = 'bRun' type="button">Entire run</button>
</div>
JSFIDDLE:https ://jsfiddle.net/shashank2104/91nwpb7a/71/
编辑:我认为每次点击都会转换圆圈但整个运行没有意义,这很糟糕。不管怎样,现在修好了。希望这足够清楚。如果没有,请告诉我。是的,请相应地匹配Step按钮单击以进行正确同步。
推荐阅读
- r - 为什么 case_when 不能返回不同长度的向量?
- windows - 批处理脚本 - 转义变量中的双引号
- java - 在java中解析(null)sql结果集值
- yocto - Yocto 从另一个配方访问 sysroot 文件
- javascript - 使用 jquery 更改图像不是实时的
- r - 将具有重复行的表从 WIDE 转换为 LONG(透视)(tidyr)
- android - RecyclerView 项目在键盘弹出时变形
- c# - 无法将 Byte[] 传递给 GraphQL 端点
- java - 网格中的机器人大 O 解释
- javascript - 寻找替换 Javascript 中的类属性