{
const _authors = Object.keys(by_author_obj);
const _data = Object.values(by_author_obj)
.map((d,i) =>{
d.map(_d =>{
_d.id = i;
return _d;
});
return d;
});
const per_height = 12;
const div = d3.create("div");
const svg = div.append("svg").attr("viewBox", [0, 0, width, per_height * (_authors.length + 2)]).attr("id", "spike-svg");
const st_year = data[data.length - 1]["発売年月"]["年"];
const ed_year = data[0]["発売年月"]["年"];
const per_x = 12;
const yearX = d3.scaleLinear()
.domain([st_year, ed_year + 1])
.range([0, per_x * (ed_year - st_year + 1)]);
const dayX = d3.scaleLinear()
.domain([1, 12])
.range([0, per_x - 1]);
const posX = function(_d){
const YM = _d["発売年月"];
return yearX(YM["年"]) + dayX(YM["月"]);
}
const posY = d3.scaleLinear()
.domain([0, _data.length])//1つ分多めにとる
.range([0, _data.length * per_height]);
// 作者毎の列
const spike_row = svg.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.selectAll("g")
.data(_data)
.enter()
.append("g")
.attr("class", (_,i) => "spike-row-" + i);
// 各スパイク
const spikes = spike_row.selectAll("line")
.data(d => d)
.enter()
.append("line")
.attr("x1", d => posX(d))
.attr("x2", d => posX(d))
.attr("y1", d => posY(d.id) + 0.5)//隙間を作成
.attr("y2", d => posY(d.id+1) - 0.5)
.attr("stroke", "#8E354A")//蘇芳(スオウ)
.attr("opacity", 0.4)//重なりがわかるように
.attr("stroke-width", 1);
// 作者名(これを先に作成しないと, デフォルトtop == svgのtop にならない)[微妙にずれる]
d3.select("#spike-div-container").remove();//既にある場合は消去
// bodyに入れないと 位置取りが面倒
d3.select("body").append("div")
.attr("id", "spike-div-container")
.style("display", "none")
.selectAll("div")
.data(_authors)
.enter()
.append("div")
.attr("class", "author-spike-div")
.style("margin", 1 + "px")//下の高さを二倍減らさなくていいのは不思議?
.style("height", (per_height - 1)+ "px") //各スパイク位置に一致するようにする
.text(d => d.length < 10? d: d.slice(0, 10) + "...");//はみ出す部分は削除
// あるスパイクに触れた場合に表示する(上の処理と同様に)
d3.select("spike-div-overtip").remove();
d3.select("body").append("div")
.attr("id", "spike-div-overtip")
.style("display", "none");
// 三年毎に表示される
function tickFormat(d){
if(d % 3 !== 0) return;
return d;
}
// 年の表示
const year_ticks = svg.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3
.axisBottom(yearX)
.ticks(ed_year - st_year + 1)
.tickFormat(tickFormat)
.tickSizeOuter(0)
);
// tickの書き方を真似して、x軸名を加えた
year_ticks.append("g")
.attr("transform", "translate(-25,0)")
.attr("opacity", 1)
.append("text")
.attr("fill", "currentColor")
.attr("y", 9)
.attr("dy", "0.71em")
.text("出版年月");
/* 表示されてない年は 突き出した棒を小さくする*/
year_ticks.selectAll(".tick")
.each( function(year,i,nodes){
const _tick = d3.select(nodes[i]);
//console.log(year, nodes[i], _tick, _tick.select("text").datum());
if(_tick.select("text").datum() % 3 !== 0){
_tick.select("line").attr("y2", 3.5);//デフォルトは6
}
});
// ticksは translateで x位置を決めて、 textなどはそれぞれ個別にyを指定する
console.log(year_ticks)
// 何もないところを触れた場合(それ以外も同時に調べる[d3 ver5より可能])
svg.on("mousemove", function(){
// 個人名の非表示
d3.select("#spike-div-overtip").style("display", "none");
const y = d3.event.offsetY;
year_ticks.attr("transform", `translate(${margin.left}, ${y + 10})`);
// div移動
const div_x = d3.event.offsetX < width/2? d3.event.offsetX + 30: d3.event.offsetX - 130;
const div_y = d3.event.target.getBoundingClientRect().top;
const names = d3.select("#spike-div-container")
.style("display", null)
.style("left", div_x + "px");
// svgの上を移動している場合のみ top位置を利用
if(d3.event.target.tagName === "svg") names.style("top", div_y + "px");
// 他の場合は、あるspikeの情報のみを表示
else{
// 全ての名前を非表示
names.style("display", "none");
// 触れているspikeについての表示
const parent = d3.event.target.parentNode;
const parent_class = parent.className.baseVal;
// spike以外なら無視
if(parent_class.indexOf("spike-row") !== -1){
const st_num_index = 1+parent_class.lastIndexOf("-")
const author_index = parseInt(parent_class.slice(st_num_index, parent_class.length), 10);
d3.select("#spike-div-overtip")
.style("display", null)
.style("left", div_x+ "px")
.style("top", (d3.event.pageY - 60) + "px")
.html("<div>" + _authors[author_index] + "</div>" +
'<div class="pub-num-spike-div-overtip">出版数: ' + _data[author_index].length + "</div>");
/*
console.log(parent, d3.select("#spike-div-overtip"), y, _authors[author_index], _data[author_index])
*/
}
}
});
return div.node()
}