javascript - 如何迭代地在每个 SVG 元素旁边添加文本
问题描述
我是 JavaScript 新手,目前正在尝试在 Vue Javascript 框架上构建一些 d3 可视化。我的问题是我已经使用图形创建了这些迭代堆叠的水平条形图svg
,并且我想添加与每个条形图或视觉对象相对应的标题或标签。我希望将label
文本放置在视觉左侧(如下图所示)或在每个视觉上方单独一行。我目前只能通过将文本附加到svg
元素来迭代地在每个栏的顶部添加标签,但这并不理想,因为它与视觉重叠。
寻求帮助以最好地将这些标签放置在视觉效果旁边(左侧或上方)
我当前负责生成 SVG 元素的方法和循环如下所示:
async genViz() {
const rawDataAllTime = await d3.csv(this.dataUrlAllTime); // import raw data currently selected
this.allData = this.processData(rawDataAllTime);
const rawDataNow = await d3.csv(this.dataUrlNow);
console.log("rawDataNow", rawDataNow);
this.nowData = this.processData(rawDataNow);
const height = 33;
const width = 800;
const color_interp = d3
.scaleLinear()
.domain([0, 1 / 3.0, 2 / 3.0, 1])
.range([
colors.accent,
colors.secondary_green,
colors.primary_teal,
colors.primary_dark,
])
.interpolate(d3.interpolateHcl);
const x = d3.scaleLinear([0, 1], [0, width]);
this.x = x;
const formatPercent = x.tickFormat(null, "%");
this.formatPercent = formatPercent;
this.svgs = [];
// loops through all stacks and generates d3 visualizations
this.allData.forEach((stack) => {
// each chart is a separate svg
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("display", "block");
this.svgs.push(svg);
let color = d3
.scaleOrdinal()
.domain(stack.map((d) => d.reason))
.range(d3.quantize((t) => color_interp(t), stack.length));
this.color = color;
svg
.append("g")
.attr("stroke", "white")
.selectAll("rect")
.data(stack)
.join("rect")
.attr("fill", (d) => color(d.reason))
.attr("x", (d) => x(d.startValue))
.attr("y", 0)
.attr("width", (d) => x(d.endValue) - x(d.startValue))
.attr("height", height)
.append("title")
.text((d) => d.type)
.attr("text-anchor","middle");
svg
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 12)
.selectAll("text")
.data(stack)
.join("text")
.attr("fill", (d) =>
d3.lab(color(d.reason)).l < 50 ? "white" : "black"
)
.attr("transform", (d) => `translate(${x(d.startValue) + 6}, 6)`)
.call((text) =>
text
.append("tspan")
.attr("class", "reason")
.attr("y", "0.7em")
.attr("font-weight", "bold")
.text((d) => d.reason)
)
.call((text) =>
text
.append("tspan")
.attr("class", "value")
.attr("x", 10)
.attr("y", "1.7em")
.attr("dx", 0)
.attr("fill-opacity", 0.7)
.text((d) => formatPercent(d.value))
)
svg
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 12)
.selectAll("text")
.data(stack)
.join("text")
.call((text) =>
text
.append("tspan")
.attr("x", 0)
.attr("y", "1.5em")
.attr("font-weight", "bold")
.text("LABEL")
.attr("fill","#f30303"))
return svg.node();
});
return this.svgs.map((svg) => svg.node());
}
编辑:能够遍历文本标签并将它们显示在 svg 元素上方。但是,我仍然无法强制文本标签与其对应的 svg 元素位于同一行。这就是我当前的template
语法:
<template>
<div class="stacked-bar">
<div class="row">
<div class="col-xs-12"><ModeToggle @toggled="toggleMode" /></div>
</div>
<div ref="d3">
<div v-for="ppe in ppe_types" v-bind:key="ppe">
<span>
<!-- text labels-->
{{ppe[0]}}
</span>
</div>
</div>
</div>
</template>
<script>
// Vue.js main code starts here
解决方案
因此,如果我从标签中正确理解,您正在使用 vue.js,而您的这个函数正在返回一个包含这些 svgs 的数组?我想你用 v-for 显示这些。所以我的解决方案是这样的:
<div v-for="(svg, i) in svgs" :key="i">
<span>Label Text</span>
<div>{{svg}}</div>
</div>
并添加一些 css 样式以强制它们成为一行。
编辑:从您更新的代码中,我收集到您有 2 个不同的数组,我以为您在一个数组中有展位,好的,这很容易解决,如果订购了它们,您可以像计算变量一样编写或返回它们。或者只是这样做(如果它们的长度相同并且订购相同)。
<div v-for="(svg, i) in svgArray" :key="i">
<span>{{labelArray[i]}}</span>
<span>{{svg}}</span>
</div>
或者
<div v-for="(label, i) in labelArray" :key="i">
<span>{{label}}</span>
<span>{{svgArray[i]}}</span>
</div>
推荐阅读
- arduino - Arduino GPS 时间和坐标值更新问题
- r - R中是否有计算多个多边形面积的函数?
- google-cloud-platform - Stackdriver 自定义提醒
- php - 未设置 Cookie,但它们出现在 PHP 标头中
- python - 使用 random.sample 将字符串替换为字典中的值
- r - 我们可以用 R 中的新字段填充列吗?
- linux - 参见 make 命令和之后所有调用的 make 文件
- c# - 使用 C# 获取存储在 azure 容器中的音频 blob 的持续时间
- python - Python 模块导入的层次结构是什么?
- create-react-app - 没有在 create-react-app 中获得生产版本