Skip to content

Instantly share code, notes, and snippets.

@shimizu
Last active February 21, 2018 03:17
Show Gist options
  • Save shimizu/867616426a9c05648d580efbbed45466 to your computer and use it in GitHub Desktop.
Save shimizu/867616426a9c05648d580efbbed45466 to your computer and use it in GitHub Desktop.
D3 Axis Tips#4" - Wrapping Tick Label
license: mit

Axis Tips #4

Tick(ラベル)をの中で改行をおこなう。

青枠はドラッグしてサイズを変更することができます。

<!DOCTYPE html>
<html lang="jp">
<head>
<style>
html, body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
}
#chart {
width: 80%;
height: 80%;
border: 8px dashed gray;
border-left: none;
border-top:none;
cursor:all-scroll;
}
#chart svg{
width: 100%;
height: 100%;
cursor: default;
}
.grid .tick line {
stroke-dasharray:1;
}
.bar {
stroke:gray;
stroke-width:1;
fill:skyblue;
}
</style>
<script src="//unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script>
</head>
<body>
<div id="chart">
<svg></svg>
</div>
<script type="text/babel">
const data = [
{title:"アメリカ合衆国の歴代\nうんちゃら\nかんちゃら比率\nあれこれ", value:80},
{title:"日本の歴代\nうんちゃら\nかんちゃら比率", value:40},
{title:"中国の歴代\nうんちゃら\nかんちゃら比率", value:60},
]
const svg = d3.select("#chart").select("svg");
const grid = svg.append("g").classed("grid", true);
const plot = svg.append("g").classed("plot", true);
const axis = svg.append("g").classed("axis", true);
const yScale = d3.scaleBand().domain(data.map(d => d.title));
const xScale = d3.scaleLinear().domain([0, 100]).nice();
render();
function render(){
const m = {top:30, left:110, right:30, bottom:30};
const w = svg.node().clientWidth || svg.node().parentNode.clientWidth;
const h = svg.node().clientHeight || svg.node().parentNode.clientHeight;
const pw = w - (m.left + m.right);
const ph = h - (m.top + m.bottom);
yScale.range([0, ph]).paddingInner(0.2);
xScale.range([0, pw]);
//axis layer
axis.attr("transform", `translate(${m.left}, ${m.top})`);
//y axis
const yAxisUpdate = axis.selectAll(".yAxis").data([null]);
const yAxisEnter = yAxisUpdate.enter().append("g").classed("yAxis", true);
const yAxis = yAxisUpdate.merge(yAxisEnter).call( d3.axisLeft().scale(yScale).tickSizeOuter(0) ); //ラベルを内向きにする
yAxis.selectAll(".tick line").remove();
yAxis.selectAll(".tick text")
.html(null) //元のtickラベルを削除
.attr("text-anchor", "start")
.attr("dominant-baseline", "middle")
.each((text, i, nodes) => {
//ラベルに適用するテキストを改行コードを基準に分割
const st = text.split("\n");
//ラベルを右揃えにするために、分割したテキストの中でもっとも長い値を取得「
const maxLength = d3.max(st, d => d.length );
//行間を設定
const lineHight = 0.6;
//分割したテキストの数から、Y座標を求めるためのスケールを設定
const ypos = d3.scaleLinear().domain([0, st.length]).range([-st.length * lineHight, st.length * lineHight]);
//分割したテキストをtspan要素で括って、もとのノードにアペンドする
const tspanUpdate = d3.select(nodes[i]).selectAll("tspan").data(st);
const tspanEnter = tspanUpdate.enter().append("tspan");
//tspanに改行のための情報を付加する
tspanEnter
.attr("dy", "1em")
.attr("y", (d,i) => ypos(i) + "em")
.attr("dx", "-" + (maxLength + 0.5) + "em")
.attr("x", (d,i) => { const l = maxLength - d.length; return l + "em"})
.text(d => d)
});
//x axis
const xAxisUpdate = axis.selectAll(".xAxis").data([null]);
const xAxisEnter = xAxisUpdate.enter().append("g").classed("xAxis", true);
const renderAxis = d3.axisBottom().scale(xScale);
const xAxis = xAxisUpdate.merge(xAxisEnter).call(renderAxis)
.attr("transform", `translate(0, ${ph})`);
xAxis.select(".domain").remove();
xAxis.selectAll(".tick line").remove();
//grid layer
grid.attr("transform", `translate(${m.left}, ${m.top})`);
//x grid
const xGridUpdate = grid.selectAll(".xGrid").data([null]);
const xGridEnter = xGridUpdate.enter().append("g").classed("xGrid", true);
const xGrid = xGridUpdate.merge(xGridEnter)
.call( d3.axisBottom().scale(xScale).tickSizeInner(-ph).tickFormat(() => null ) )
.attr("transform", `translate(0, ${ph})`);
xGrid.select(".domain").remove();
//plot layer
plot.attr("transform", `translate(${m.left}, ${m.top})`);
//bar
const barsUpdate = plot.selectAll(".bar").data(data);
const barsEnter = barsUpdate.enter().append("rect").classed("bar", true);
const bars = barsUpdate.merge(barsEnter)
.attr("height", yScale.bandwidth())
.attr("width", d => xScale(d.value))
.attr("y", d => yScale(d.title))
.attr("x", 0.5) //storke-width分のズレを修正
;
}
//divエレメントをドラッグでリサイズできるようにする。
const dispatch = d3.dispatch("resize");
dispatch.on("resize", render);
setResizeControler();
function setResizeControler(){
const drag = d3.drag()
.on("drag", resized)
d3.select("#chart")
.call(drag);
function resized(e){
const s = d3.event.sourceEvent;
const w = (s.pageX < 300) ? 300 : s.pageX;
const h = (s.pageY < 200) ? 200 : s.pageY;
console.log(h)
d3.select(this)
.style("width", `${w}px`)
.style("height", `${h}px`)
.attr("data-test", "test")
dispatch.call("resize");
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment