Я создал спиральную визуализацию с помощью d3js. Живой пример здесь
Я пытаюсь создать (в основном для выделения) подразделы спирали.
Спираль определяется следующим образом:
const start = 0
const end = 2.25
const theta = function(r) {
return numSpirals * Math.PI * r
}
const radius = d3.scaleLinear()
.domain([start, end])
.range([20, r])
const spiral = d3.radialLine()
.curve(d3.curveCardinal)
.angle(theta)
.radius(radius)
const points = d3.range(start, end + 0.001, (end - start) / 1000)
const path = g.append("path")
.datum(points)
.attr("id", "spiral")
.attr("d", spiral)
.style("fill", "none")
.style("stroke", "steelblue");
Некоторые случайные точки помещаются в спираль, используя что-то вроде:
const positionScale = d3.scaleLinear()
.domain(d3.extent(mockedData, (d, i) => i))
.range([0, spiralLength]);
const circles = g.selectAll("circle")
.data(mockedData)
.enter()
.append("circle")
.attr("cx", (d,i) => {
const linePos = positionScale(i)
const posOnLine = path.node().getPointAtLength(linePos)
d.cx = posOnLine.x
d.cy = posOnLine.y
return d.cx;
})
.attr("cy", d => d.cy)
.attr("r", d => circleRadiusScale(d.value))
Если начало и конец спирали равен [0, 2.25], легко получить подраздел спирали от 0 до 1, создав новый набор точек от 0 до 1 (вместо 0 до 2,25):
const pointSubSpiral = d3.range(0, 1 + 0.001, 1 / 1000)
Проблема у меня возникает, когда я пытаюсь создать подраздел спирали на основе точек данных. Например, от 0 до положения точки 3. Линейная шкала не работает:
const spiralSectionScale = d3.scaleLinear()
.range([start, end])
.domain([0, mockedData.length])
const spiralEnd = spiralSectionScale(i)
const sectionPoints = d3.range(0, 1 + 0.001, 1 / 1000)
const path2 = g.append("path")
.datum(sectionPoints)
.attr("id", "spiral-section")
.attr("d", spiral)
.style("fill", "none")
.style("stroke", "red")
.style("stroke-width", "1.2em")
.style("opacity", "0.2")
.style("pointer-events", "none")
Есть ли способ преобразовать значения в области данных в спиральную область?
ОБНОВЛЕНИЕ : Основываясь на ответе @ rioV8, приведенном ниже, мне удалось получить работающие участки спирали. В основном путем создания бинарного поиска по радиусу узла:
function findSpiralSection(targetRadius, start, end) {
const endSection = (end + start) / 2
const endSectionRadius = radius(endSection)
if (Math.abs(targetRadius - endSectionRadius) < 0.1) {
return endSection
}
if ((targetRadius - endSectionRadius) > 0) {
return findSpiralSection(targetRadius, endSection, end)
} else {
return findSpiralSection(targetRadius, start, endSection)
}
}
function higlightSubSpiral(d, i) {
const linePos = positionScale(i);
const targetNode = path.node().getPointAtLength(linePos);
const nodeRadius = Math.sqrt((targetNode.x * targetNode.x) + (targetNode.y * targetNode.y))
const bestEndSection = findSpiralSection(nodeRadius, start, end);
const sectionPoints = d3.range(0, bestEndSection + 0.001, bestEndSection / 1000)
const path2 = g.append("path")
.datum(sectionPoints)
.attr("id", "spiral-section")
.attr("d", spiral)
.style("fill", "none")
.style("stroke", "red")
.style("stroke-width", "1.2em")
.style("opacity", "0.2")
.style("pointer-events", "none")
}