问题:

我正在尝试在代码提示中为每个工具提示添加一个具有数据集第一个索引的data-data属性,但是我一生都无法弄清楚如何根据在数据集上。

例如,我想要达到以下效果:

const tip = d3.tip()
    .attr('data-date', d => d[0])
    //...


这是一个代码片段:



//need to fix tooltip data-date attr.. don't know how I'll do that yet though

const endpoint =
	"https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json";

d3.json(endpoint).then(data => {
	const gc = d3.select(document.getElementById("graph-container")),
		dataset = data.data,
		canvasWidth = 900,
		canvasHeight = 477,
		padding = 50,
		years = dataset.map(s => s[0].slice(0, 4)),
		xScale = d3
			.scaleLinear()
			.domain([0, dataset.length])
			.range([padding, canvasWidth - padding]),
		yScale = d3
			.scaleLinear()
			.domain([0, d3.max(dataset, d => d[1])])
			.range([padding, canvasHeight - padding]),
		tip = d3 //making a tooltip
			.tip()
			.attr("id", "tooltip")
			.direction("e")
			.offset([0, 25])
			.html(
				d =>
					`${d[0].slice(0, 4)} Q${
						d[0].slice(5, 7) === "01"
							? "1"
							: d[0].slice(5, 7) === "04"
								? "2"
								: d[0].slice(5, 7) === "07"
									? "3"
									: d[0].slice(5, 7) === "10" ? "4" : null
					}<br />$${d[1]} Billion`
			),
		xAxis = d3
			.axisBottom(
				d3
					.scaleLinear()
					.domain([d3.min(years), d3.max(years)])
					.range([padding, canvasWidth - padding])
			)
			.tickFormat(d3.format("d")),
		yAxis = d3.axisLeft(
			d3
				.scaleLinear()
				.domain([0, d3.max(dataset, d => d[1])])
				.range([canvasHeight - padding, padding])
		); //not sure how to make this work without redefining the range. point is, however, it works... so... take that

	gc //making the title element
		.append("div")
		.attr("id", "title")
		.text("National Income and Product Accounts of the United States (NIPA)");

	gc //making the graph
		.append("svg")
		.attr("id", "canvas")
		.attr("width", canvasWidth)
		.attr("height", canvasHeight)
		.call(tip)
		.selectAll("rect")
		.data(dataset)
		.enter()
		.append("rect")
		.attr("class", "bar")
		.style('fill', (d, i) => d[1] <= dataset[i === 0 ? 0 : i - 1][1] ? '#f92727' : '#00cc58')
		.attr("x", (d, i) => xScale(i))
		.attr("y", d => canvasHeight - yScale(d[1]))
		.attr("width", canvasWidth / dataset.length)
		.attr("height", d => yScale(d[1]) - padding)
		.attr("data-date", d => d[0])
		.attr("data-gdp", d => d[1])
		.on("mouseover", tip.show)
		.on("mouseout", tip.hide);

	d3 //add x-axis
		.select(document.getElementById("canvas"))
		.append("g")
		.attr("id", "x-axis")
		.attr("transform", `translate(0, ${canvasHeight - padding})`)
		.call(xAxis);

	d3 //add y-axis
		.select(document.getElementById("canvas"))
		.append("g")
		.attr("id", "y-axis")
		.attr("transform", `translate(${padding}, 0)`)
		.call(yAxis);
});

@import url('https://fonts.googleapis.com/css?family=Lato');

* {
	overflow: hidden;
	font-family: 'Lato';
}

html, body {
	padding: 0;
	margin: 0;
}

#container {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	height: 100vh;
	background-image: linear-gradient(to bottom right, white, #ffffe6);
}

#graph-container {
	box-shadow: 2px 2px 10px 1px gray;
	height: 550px;
	width: 950px;
	border-radius: 5px;
	background-color: white;
	display: flex;
	flex-direction: column;
	align-items: center;
}

#title {
	text-align: center;
	padding-top: 15px;
	font-size: 20px;
	width: 100%;
	padding-bottom: 15px;
	box-shadow: 0 0 5px 0 gray;
}

#canvas {
	background-color: transparent;
	margin-top: 15px;
}

.bar:hover {
	fill: yellow;
}

#tooltip {
	background-color: orange;
	padding: 15px;
	border-radius: 5px;
	min-width: 100px;
	text-align: center;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="container">
	<div id="graph-container"></div>
</div>





我尝试将数据集附加到tip变量并通过.attr传递,但是不幸的是,数据集只能通过.html传递而不会中断。

我尝试过移动.call提示以使数据通过,但这也不起作用。

我必须使用.attr,并且不能通过将属性附加到生成的div / span / etc中来伪造它。

有人有想法么?

最佳答案

d3-tip是一个非常独立的实体,因此,如果要执行此操作,基本上就必须对其进行破解。没有通过官方API做到这一点的好方法。在html函数期间,您可以操纵tip DOM元素并使用当前数据项向其添加属性:

            .html(
                d => {
                // slightly horrible hack
                d3.select('#tooltip').attr('data-date', d[0]);
                    return `${d[0].slice(0, 4)} Q${
                        d[0].slice(5, 7) === "01"
                            ? "1"
                            : d[0].slice(5, 7) === "04"
                                ? "2"
                                : d[0].slice(5, 7) === "07"
                                    ? "3"
                                    : d[0].slice(5, 7) === "10" ? "4" : null
                    }<br />$${d[1]} Billion`
            }),


集成到整个代码中:



//need to fix tooltip data-date attr.. don't know how I'll do that yet though

const endpoint =
	"https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json";

d3.json(endpoint).then(data => {
	const gc = d3.select(document.getElementById("graph-container")),
		dataset = data.data,
		canvasWidth = 900,
		canvasHeight = 477,
		padding = 50,
		years = dataset.map(s => s[0].slice(0, 4)),
		xScale = d3
			.scaleLinear()
			.domain([0, dataset.length])
			.range([padding, canvasWidth - padding]),
		yScale = d3
			.scaleLinear()
			.domain([0, d3.max(dataset, d => d[1])])
			.range([padding, canvasHeight - padding]),
		tip = d3 //making a tooltip
			.tip()
			.attr("id", "tooltip")
			.direction("e")
			.offset([0, 25])
			.html(
				d => {
                d3.select('#tooltip').attr('data-date', d[0]);
					return `${d[0].slice(0, 4)} Q${
						d[0].slice(5, 7) === "01"
							? "1"
							: d[0].slice(5, 7) === "04"
								? "2"
								: d[0].slice(5, 7) === "07"
									? "3"
									: d[0].slice(5, 7) === "10" ? "4" : null
					}<br />$${d[1]} Billion`
			}),
		xAxis = d3
			.axisBottom(
				d3
					.scaleLinear()
					.domain([d3.min(years), d3.max(years)])
					.range([padding, canvasWidth - padding])
			)
			.tickFormat(d3.format("d")),
		yAxis = d3.axisLeft(
			d3
				.scaleLinear()
				.domain([0, d3.max(dataset, d => d[1])])
				.range([canvasHeight - padding, padding])
		); //not sure how to make this work without redefining the range. point is, however, it works... so... take that

	gc //making the title element
		.append("div")
		.attr("id", "title")
		.text("National Income and Product Accounts of the United States (NIPA)");

	gc //making the graph
		.append("svg")
		.attr("id", "canvas")
		.attr("width", canvasWidth)
		.attr("height", canvasHeight)
		.call(tip)
		.selectAll("rect")
		.data(dataset)
		.enter()
		.append("rect")
		.attr("class", "bar")
		.style('fill', (d, i) => d[1] <= dataset[i === 0 ? 0 : i - 1][1] ? '#f92727' : '#00cc58')
		.attr("x", (d, i) => xScale(i))
		.attr("y", d => canvasHeight - yScale(d[1]))
		.attr("width", canvasWidth / dataset.length)
		.attr("height", d => yScale(d[1]) - padding)
		.attr("data-date", d => d[0])
		.attr("data-gdp", d => d[1])
		.on("mouseover", tip.show)
		.on("mouseout", tip.hide);

	d3 //add x-axis
		.select(document.getElementById("canvas"))
		.append("g")
		.attr("id", "x-axis")
		.attr("transform", `translate(0, ${canvasHeight - padding})`)
		.call(xAxis);

	d3 //add y-axis
		.select(document.getElementById("canvas"))
		.append("g")
		.attr("id", "y-axis")
		.attr("transform", `translate(${padding}, 0)`)
		.call(yAxis);
});

@import url('https://fonts.googleapis.com/css?family=Lato');

* {
	overflow: hidden;
	font-family: 'Lato';
}

html, body {
	padding: 0;
	margin: 0;
}

#container {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	height: 100vh;
	background-image: linear-gradient(to bottom right, white, #ffffe6);
}

#graph-container {
	box-shadow: 2px 2px 10px 1px gray;
	height: 550px;
	width: 950px;
	border-radius: 5px;
	background-color: white;
	display: flex;
	flex-direction: column;
	align-items: center;
}

#title {
	text-align: center;
	padding-top: 15px;
	font-size: 20px;
	width: 100%;
	padding-bottom: 15px;
	box-shadow: 0 0 5px 0 gray;
}

#canvas {
	background-color: transparent;
	margin-top: 15px;
}

.bar:hover {
	fill: yellow;
}

#tooltip {
	background-color: orange;
	padding: 15px;
	border-radius: 5px;
	min-width: 100px;
	text-align: center;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="container">
	<div id="graph-container"></div>
</div>

关于javascript - 将动态Attr()添加到d3.tip,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52416779/

10-11 14:41