为每个分类值分配不同的 y 坐标
Assign distinct y coordinate to each categorical value
我明确要求在 d3 上下文中计算 y 坐标,但我正在努力...
a) 找到 d3(缩放?)组件和使用模式来提供解决方案
b) 确定任何可导航的 d3 API 资源,这将帮助我找到 a)
我有一个事件列表,这些事件具有开始时间和结束时间,并且每个事件都与它们按顺序执行的过程相关联。将其呈现为多轨界面(有点像音频编辑器或甘特图)很自然,其中每个 process/track 都分配有自己的水平泳道,并且事件根据它们的开始水平排列和结束时间。它最终可能看起来有点像这样 view from a research publication
事件数据项引用了它们的进程 ID(在图中显示的进程 ID 是 M1、M2,事件是标有数字的小框)。我知道每个事件的开始和结束时间(确定它们的 x 坐标和宽度),但我需要将操作的矩形放在正确的进程行(y 坐标)中。
事件列表将在开始和结束时不断更新,并可能在未来由 filter/brush 调解。
行数随着进程数的变化而变化。出于这个原因,只有在加入事件列表(并遇到它们引用的所有进程 ID)之后,您才能知道需要多少行、行高以及每个事件的 y 比例位置应该是多少。当一个新的事件项进入指向新进程 ID 的选择时,比例尺应该重新调整以添加一个额外的行。当它退出选择时,它可能是该进程行中的最后一个,因此该行应该消失。
是否有一种模式可以根据事件数据动态列表的(分类)进程 ID 动态分配事件行的 y 坐标?
如何为这种情况找到模式和解决方案?
这是一个使用以下数据模型的简单片段:
[
{
label: string; // Row label
color: string; // Row color
items: [ { label: string; start: number; end: number; }, ...];
},
...
]
代码段使用 d3.scaleLinear
和 d3.axisBottom
例程。
注意:我使用 _top
因为(出于某种神秘原因)top
已经被使用了......我想这是 D3 V5,建议使用V6.
const data = [
{
label: 'M1',
color: 'red',
items: [
{label: 'A', start: 10, end: 12},
{label: 'B', start: 15, end: 20}
]
},
{
label: 'M2',
color: 'orange',
items: [
{label: 'C', start: 0, end: 4},
{label: 'D', start: 4, end: 6},
{label: 'E', start: 11, end: 17}
]
},
{
label: 'M3',
color: 'yellow',
items: [
{label: 'F', start: 0, end: 3},
{label: 'G', start: 3, end: 9},
{label: 'H', start: 9, end: 14}
]
}
];
const ticks = 25;
const left = 50;
const _top = 50;
const rowHeight = 20;
const labelWidth = 30;
const bottom = _top + data.length * rowHeight;
const svg = d3.select("svg");
const xScale = d3.scaleLinear()
.domain([0, ticks])
.range([0, 300]);
const xAxis = d3.axisBottom()
.scale(xScale);
svg.append("g")
.attr('transform', `translate(${left}, ${bottom - 1})`)
.call(xAxis);
let i, j;
for (i = 0; i <= ticks; i++)
svg.append('line')
.attr('x1', xScale(i) + left)
.attr('x2', xScale(i) + left)
.attr('y1', _top)
.attr('y2', bottom)
.style('stroke', 'black');
for (i = 0; i < data.length; i++) {
svg.append('line')
.attr('x1', left)
.attr('x2', xScale(ticks) + left)
.attr('y1', _top + i * rowHeight)
.attr('y2', _top + i * rowHeight)
.style('stroke', 'black');
svg.append('rect')
.attr('x', left - labelWidth)
.attr('y', _top + i * rowHeight)
.attr('width', labelWidth)
.attr('height', rowHeight)
.style('fill', data[i].color)
.style('stroke', 'black')
svg.append('text')
.text(data[i].label)
.attr('x', left - labelWidth / 2)
.attr('y', _top + (i + 0.5) * rowHeight)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black');
const items = data[i].items;
for (j = 0; j < items.length; j++) {
const x = left + xScale(items[j].start);
const width = xScale(items[j].end) - xScale(items[j].start);
svg.append('rect')
.attr('x', x)
.attr('y', _top + i * rowHeight)
.attr('width', width)
.attr('height', rowHeight)
.style('fill', data[i].color)
.style('stroke', 'black')
svg.append('text')
.text(items[j].label)
.attr('x', x + width / 2)
.attr('y', _top + (i + 0.5) * rowHeight)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black');
}
}
text {
font-family: 'Ubuntu';
font-size: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="200">
</svg>
我明确要求在 d3 上下文中计算 y 坐标,但我正在努力...
a) 找到 d3(缩放?)组件和使用模式来提供解决方案
b) 确定任何可导航的 d3 API 资源,这将帮助我找到 a)
我有一个事件列表,这些事件具有开始时间和结束时间,并且每个事件都与它们按顺序执行的过程相关联。将其呈现为多轨界面(有点像音频编辑器或甘特图)很自然,其中每个 process/track 都分配有自己的水平泳道,并且事件根据它们的开始水平排列和结束时间。它最终可能看起来有点像这样 view from a research publication
事件数据项引用了它们的进程 ID(在图中显示的进程 ID 是 M1、M2,事件是标有数字的小框)。我知道每个事件的开始和结束时间(确定它们的 x 坐标和宽度),但我需要将操作的矩形放在正确的进程行(y 坐标)中。
事件列表将在开始和结束时不断更新,并可能在未来由 filter/brush 调解。
行数随着进程数的变化而变化。出于这个原因,只有在加入事件列表(并遇到它们引用的所有进程 ID)之后,您才能知道需要多少行、行高以及每个事件的 y 比例位置应该是多少。当一个新的事件项进入指向新进程 ID 的选择时,比例尺应该重新调整以添加一个额外的行。当它退出选择时,它可能是该进程行中的最后一个,因此该行应该消失。
是否有一种模式可以根据事件数据动态列表的(分类)进程 ID 动态分配事件行的 y 坐标?
如何为这种情况找到模式和解决方案?
这是一个使用以下数据模型的简单片段:
[
{
label: string; // Row label
color: string; // Row color
items: [ { label: string; start: number; end: number; }, ...];
},
...
]
代码段使用 d3.scaleLinear
和 d3.axisBottom
例程。
注意:我使用 _top
因为(出于某种神秘原因)top
已经被使用了......我想这是 D3 V5,建议使用V6.
const data = [
{
label: 'M1',
color: 'red',
items: [
{label: 'A', start: 10, end: 12},
{label: 'B', start: 15, end: 20}
]
},
{
label: 'M2',
color: 'orange',
items: [
{label: 'C', start: 0, end: 4},
{label: 'D', start: 4, end: 6},
{label: 'E', start: 11, end: 17}
]
},
{
label: 'M3',
color: 'yellow',
items: [
{label: 'F', start: 0, end: 3},
{label: 'G', start: 3, end: 9},
{label: 'H', start: 9, end: 14}
]
}
];
const ticks = 25;
const left = 50;
const _top = 50;
const rowHeight = 20;
const labelWidth = 30;
const bottom = _top + data.length * rowHeight;
const svg = d3.select("svg");
const xScale = d3.scaleLinear()
.domain([0, ticks])
.range([0, 300]);
const xAxis = d3.axisBottom()
.scale(xScale);
svg.append("g")
.attr('transform', `translate(${left}, ${bottom - 1})`)
.call(xAxis);
let i, j;
for (i = 0; i <= ticks; i++)
svg.append('line')
.attr('x1', xScale(i) + left)
.attr('x2', xScale(i) + left)
.attr('y1', _top)
.attr('y2', bottom)
.style('stroke', 'black');
for (i = 0; i < data.length; i++) {
svg.append('line')
.attr('x1', left)
.attr('x2', xScale(ticks) + left)
.attr('y1', _top + i * rowHeight)
.attr('y2', _top + i * rowHeight)
.style('stroke', 'black');
svg.append('rect')
.attr('x', left - labelWidth)
.attr('y', _top + i * rowHeight)
.attr('width', labelWidth)
.attr('height', rowHeight)
.style('fill', data[i].color)
.style('stroke', 'black')
svg.append('text')
.text(data[i].label)
.attr('x', left - labelWidth / 2)
.attr('y', _top + (i + 0.5) * rowHeight)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black');
const items = data[i].items;
for (j = 0; j < items.length; j++) {
const x = left + xScale(items[j].start);
const width = xScale(items[j].end) - xScale(items[j].start);
svg.append('rect')
.attr('x', x)
.attr('y', _top + i * rowHeight)
.attr('width', width)
.attr('height', rowHeight)
.style('fill', data[i].color)
.style('stroke', 'black')
svg.append('text')
.text(items[j].label)
.attr('x', x + width / 2)
.attr('y', _top + (i + 0.5) * rowHeight)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('fill', 'black');
}
}
text {
font-family: 'Ubuntu';
font-size: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="200">
</svg>