Built with blockbuilder.org
forked from GitNoise's block: 2 axis to 1 axis and back again!
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
line {
stroke: black;
stroke-opacity: 0.7
}
path {
stroke-width: 1px;
fill: none;
}
svg {
margin: 20px;
}
circle.icon {
fill-opacity: 0;
}
.position circle, .position path {
fill-opacity: 0;
stroke-opacity: 0;
}
.field {
fill: #efefef;
stroke: #969696;
}
</style>
</head>
<body>
<button onclick="move()">Move</button>
<script>
const height = 300;
const width = 300;
const radius = 15;
const margin = radius * 3 + 4;
// Feel free to change or delete any of the code you see in this editor!
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
const axisData = [
{id:"horisontal", x1: margin, x2: width-margin, y1: height/2, y2:height/2},
{id: "vertical", x1: width/2, x2: width/2, y1: margin, y2:height-margin},
];
const scaleY = d3.scaleLinear()
.domain([0, 100])
.range([margin, height - margin]);
const scaleX = d3.scaleLinear()
.domain([0, 100])
.range([margin, width - margin]);
const rand = () => Math.random() * 101
const palette = ["#b6ae44",
"#8460cc",
"#61b858",
"#c858a9",
"#5f7c3a",
"#7789cd",
"#ce4a3c",
"#4cb6a9",
"#c56179",
"#c37e3f"];
const dotData1 = [
{id: "c1", "cx": 50, "cy": rand()},
{id: "c2", "cx": 50, "cy": rand()},
{id: "c3", "cx": 50, "cy": rand()},
{id: "c4", "cx": 50, "cy": rand()},
{id: "c5", "cx": 50, "cy": rand()},
{id: "c6", "cx": 50, "cy": rand()},
{id: "c7", "cx": 50, "cy": rand()},
{id: "c8", "cx": 50, "cy": rand()},
]
const dotData2 = [
{id: "c1", "cx": rand(), "cy": rand()},
{id: "c2", "cx": rand(), "cy": rand()},
{id: "c3", "cx": rand(), "cy": rand()},
{id: "c4", "cx": rand(), "cy": rand()},
{id: "c5", "cx": rand(), "cy": rand()},
{id: "c6", "cx": rand(), "cy": rand()},
{id: "c7", "cx": rand(), "cy": rand()},
{id: "c8", "cx": rand(), "cy": rand()},
]
const iconsData = [
{id: "i1", color: palette[0]},
{id: "i2", color: palette[1]},
{id: "i3", color: palette[2]},
{id: "i4", color: palette[3]},
{id: "i5", color: palette[4]},
{id: "i6", color: palette[5]},
{id: "i7", color: palette[6]},
{id: "i8", color: palette[7]},
]
const t = d3.transition()
.duration(1000);
function drawField() {
svg.append("rect")
.classed("field", true)
.attr("x", scaleX.range()[0])
.attr("y", scaleY.range()[0])
.attr("width", scaleX.range()[1] - scaleX.range()[0])
.attr("height", scaleY.range()[1] - scaleY.range()[0])
}
function drawAxis(data) {
const d = svg.selectAll("line")
.data(data, key=>key.id);
d.enter()
.append("line")
.attr("x1", d => d.x1)
.attr("x2", d => d.x2)
.attr("y1", d => d.y1)
.attr("y2", d => d.y2)
}
function drawArc(x1, y1, x2, y2, r) {
var path = d3.path();
path.moveTo(x1, y1);
path.quadraticCurveTo(
x1 + (x1 < width / 2 ? 50 : -50),
y1 + (y2 > y1 ? 50 : -50),
x2,
y2);
return path.toString();
}
function drawPositions(data) {
const d = svg.selectAll("g.position").data(data);
// update
d.select(".point")
.transition(t)
.attr("cx", d => d.endCx)
.attr("cy", d => d.endCy);
d.select("path")
.transition(t)
.attr('d', d => drawArc(d.startCx, d.startCy, d.endCx, d.endCy))
// enter
const g = d.enter().append("g").classed("position", true);
g.append("circle")
.classed("point", true)
.attr("cx", d => d.endCx)
.attr("cy", d => d.endCy)
.attr("r", 3)
.style("fill", d => d.color)
.transition(t)
.style("fill-opacity", 0.8)
g.append("path")
.attr('d', d => drawArc(d.startCx, d.startCy, d.endCx, d.endCy))
.style("stroke", d => d.color)
.transition(t)
.style("stroke-opacity", 0.8)
}
function drawIcon(data) {
svg.selectAll("circle.icon")
.data(data, d => d.id)
.enter()
.append("circle")
.classed("icon", true)
.attr("cx", d => d.cx)
.attr("cy", d => d.cy)
.attr("r", radius)
.style("fill", d => d.color)
.transition(t)
.style("fill-opacity", 1)
}
function createIconPositionsData(data) {
const iconsOnEachSide = Math.floor(data.length / 2) - 1;
const distanceY = (scaleY.range()[1] - scaleY.range()[0]) / iconsOnEachSide;
const offsetFromTop = (height - iconsOnEachSide * distanceY) / 2;
data = data.map((d, i) => {
d.cx = i <= iconsOnEachSide ? 0 + radius : width - radius;
d.cy = (i % (iconsOnEachSide + 1)) * distanceY + offsetFromTop;
return d;
});
return data;
}
function mergeDotAndIconData(dotData, iconsData) {
const result = [];
dotData.forEach((d, i) =>
result.push({
id: "p" + i,
color: iconsData[i].color,
endCx: scaleX(d.cx),
endCy: scaleX(d.cy),
startCx: iconsData[i].cx,
startCy: iconsData[i].cy,
}));
return result;
}
const iconPositionData = createIconPositionsData(iconsData);
const positionData = mergeDotAndIconData(dotData1, iconPositionData);
drawField();
drawAxis(axisData);
drawPositions(positionData);
drawIcon(iconPositionData)
let first = true;
function move() {
const positionData = mergeDotAndIconData(
first ? dotData2 : dotData1,
iconPositionData);
drawPositions(positionData);
first = !first;
}
</script>
</body>
https://d3js.org/d3.v4.min.js