|
/** |
|
* |
|
* @module createVBarChart |
|
* @desc セレクター上に棒グラフを描画します。 |
|
*/ |
|
|
|
function createVBarChart(){ |
|
"use strict" |
|
|
|
var _chartWidth,_chartHeight |
|
|
|
|
|
var _margin = {top:0, left:0, bottom:0, right:0}; |
|
|
|
var _x = function(){ return d }, |
|
_y = function(){ return d } |
|
|
|
var _xScale = d3.scaleBand(), |
|
_yScale = d3.scaleLinear() |
|
|
|
var _xScaleDomain, _yScaleDomain, |
|
_xScaleRange, _yScaleRange |
|
|
|
var _xScalePaddingInner = 0.1, |
|
_xScalePaddingOuter = 0.5 |
|
|
|
var _xAxisLabel,_yAxisLabel |
|
|
|
|
|
var _xAxisGridVisible = false, |
|
_yAxisGridVisible = false |
|
|
|
|
|
var _xAxisLabelOption = {x:0, y:0, "text-anchor":"middle", "dominant-baseline":"auto"}, |
|
_yAxisLabelOption = {x:0, y:0, "text-anchor":"start", "dominant-baseline":"auto"} |
|
|
|
|
|
var _yTickValues, _xTickValues |
|
|
|
|
|
var _transitionObject = d3.transition().duration(0) |
|
|
|
var _responsive = true |
|
|
|
|
|
var _dispatch = d3.dispatch("mouseover","mousemove", "mouseout", "click"); |
|
|
|
|
|
function exports(_selection) { |
|
|
|
|
|
_selection.each(function(_data){ |
|
var isHash = function(value) { |
|
return value.toString() === '[object Object]'; |
|
} |
|
var isArray = Array.isArray || function(value) { |
|
return value.toString() === '[object Array]'; |
|
} |
|
|
|
var parentNode = _selection.node() |
|
var selectedSVG = _selection.selectAll("svg") |
|
.data(["dummy"]) |
|
|
|
|
|
var newSVG = selectedSVG.enter().append("svg") |
|
|
|
var svg = selectedSVG.merge(newSVG) |
|
|
|
svg.attr("class", "vbarChart") |
|
|
|
|
|
|
|
var axisLayer = svg.append("g").classed("axisLayer", true) |
|
var chartLayer = svg.append("g").classed("chartLayer", true) |
|
|
|
|
|
var parentWidth, parentHeight |
|
|
|
main(_data) |
|
|
|
if(_responsive) setReSizeEvent() |
|
|
|
|
|
function main(data) { |
|
setSize() |
|
|
|
if(isHash(data)){ |
|
var tmp = [] |
|
Object.keys(data).forEach(function(key){ |
|
tmp.push(data[key]) |
|
}) |
|
setScale(Array.prototype.concat.apply([], tmp)) |
|
|
|
} else if (isArray(data)){ |
|
setScale(data) |
|
} |
|
|
|
if(_yAxisGridVisible) renderYAxisGrid() |
|
if(_xAxisGridVisible) renderXAxisGrid() |
|
|
|
|
|
renderYAxis() |
|
renderXAxis() |
|
|
|
renderYAxisLabel() |
|
renderXAxisLabel() |
|
|
|
|
|
renderBarChart(data) |
|
|
|
} |
|
|
|
function setReSizeEvent() { |
|
var resizeTimer; |
|
var interval = Math.floor(1000 / 60 * 10); |
|
|
|
window.addEventListener('resize', function (event) { |
|
if (resizeTimer !== false) { |
|
clearTimeout(resizeTimer); |
|
} |
|
resizeTimer = setTimeout(function () { |
|
main(_data) |
|
}, interval); |
|
}); |
|
} |
|
|
|
function setSize(args) { |
|
parentWidth = parentNode.clientWidth |
|
parentHeight = parentNode.clientHeight |
|
|
|
_chartWidth = parentWidth - (_margin.left + _margin.right) |
|
_chartHeight = parentHeight - (_margin.top + _margin.bottom) |
|
|
|
|
|
svg |
|
.attr("width", parentWidth) |
|
.attr("height", parentHeight) |
|
|
|
axisLayer |
|
.attr("width", parentWidth) |
|
.attr("height", parentHeight) |
|
|
|
chartLayer |
|
.attr("width", _chartWidth) |
|
.attr("height", _chartHeight) |
|
.attr("transform", "translate("+[_margin.left, _margin.top]+")") |
|
} |
|
|
|
function setScale(data){ |
|
var xMap = data.map(function(d){ return _x(d) }).sort(function(a, b){ return a -b }) |
|
var yMax = d3.max(data, function(d){ return _y(d) }) |
|
var yMin = d3.min(data, function(d){ return _y(d) }) |
|
|
|
if (yMin < 0){ |
|
var yExtent = [yMin, yMax] |
|
}else{ |
|
var yExtent = [0, yMax] |
|
} |
|
|
|
|
|
|
|
if (!_xScaleDomain) _xScaleDomain = xMap |
|
if (!_yScaleDomain) _yScaleDomain = yExtent |
|
_xScaleRange = [0, _chartWidth] |
|
_yScaleRange = [_chartHeight, 0] |
|
|
|
_xScale.domain(_xScaleDomain).paddingInner(_xScalePaddingInner).paddingOuter(_xScalePaddingOuter) |
|
_yScale.domain(_yScaleDomain) |
|
_xScale.range(_xScaleRange) |
|
_yScale.range(_yScaleRange) |
|
|
|
} |
|
|
|
function renderYAxis() { |
|
var yAxisCall = d3.axisLeft(_yScale) |
|
.tickSizeOuter(0) |
|
|
|
if (_yTickValues) yAxisCall.tickValues(_yTickValues) |
|
|
|
var yAxis = axisLayer.selectAll(".axis.y") |
|
.data(["dummy"]) |
|
|
|
var newYAxis = yAxis.enter().append("g") |
|
|
|
newYAxis.merge(yAxis) |
|
.transition(_transitionObject) |
|
.attr("transform", "translate("+[_margin.left, _margin.top]+")") |
|
.attr("class", "axis y") |
|
.call(yAxisCall); |
|
|
|
} |
|
|
|
function renderYAxisGrid() { |
|
var yAxisCall = d3.axisLeft(_yScale) |
|
.tickSizeOuter(0) |
|
.tickSizeInner(-_chartWidth) |
|
.tickFormat(function(d){ return null }) |
|
|
|
|
|
if (_yTickValues) yAxisCall.tickValues(_yTickValues) |
|
|
|
var yAxis = axisLayer.selectAll(".grid.y") |
|
.data(["dummy"]) |
|
|
|
var newYAxis = yAxis.enter().append("g") |
|
.attr("class", "grid y") |
|
|
|
newYAxis.merge(yAxis) |
|
.transition(_transitionObject) |
|
.attr("transform", "translate("+[_margin.left, _margin.top]+")") |
|
.call(yAxisCall); |
|
|
|
} |
|
|
|
function renderXAxis() { |
|
var xAxisCall = d3.axisBottom(_xScale) |
|
.tickSizeOuter(0) |
|
|
|
if (_xTickValues) xAxisCall.tickValues(_xTickValues) |
|
|
|
|
|
var xAxis = axisLayer.selectAll(".axis.x") |
|
.data(["dummy"]) |
|
|
|
var newXAxis = xAxis.enter().append("g") |
|
|
|
newXAxis.merge(xAxis) |
|
.transition(_transitionObject) |
|
.attr("transform", "translate("+[_margin.left, _chartHeight+_margin.top]+")") |
|
.attr("class", "axis x") |
|
.call(xAxisCall) |
|
.each(function(){ |
|
d3.select(this).select(".domain") |
|
.attr("transform", "translate("+[0,-_chartHeight + _yScale(0)]+")") |
|
}) |
|
|
|
|
|
} |
|
|
|
function renderXAxisGrid() { |
|
var xAxisCall = d3.axisBottom(_xScale) |
|
.tickSizeOuter(0) |
|
.tickSizeInner(-_chartHeight) |
|
.tickFormat(function(d){ return null }) |
|
|
|
|
|
|
|
if (_xTickValues) xAxisCall.tickValues(_xTickValues) |
|
|
|
|
|
var xAxis = axisLayer.selectAll(".grid.x") |
|
.data(["dummy"]) |
|
|
|
var newXAxis = xAxis.enter().append("g") |
|
|
|
newXAxis.merge(xAxis) |
|
.transition(_transitionObject) |
|
.attr("transform", "translate("+[_margin.left, _chartHeight+_margin.top]+")") |
|
.attr("class", "grid x") |
|
.call(xAxisCall); |
|
|
|
} |
|
|
|
|
|
function renderYAxisLabel() { |
|
var yAxisLabel = axisLayer.selectAll(".label.y") |
|
.data(["dummy"]) |
|
|
|
var newYAxisLabel = yAxisLabel.enter().append("text").attr("class", "label y") |
|
|
|
yAxisLabel.merge(newYAxisLabel) |
|
.text(function(d){ return _yAxisLabel }) |
|
.attr("x", _yAxisLabelOption.x) |
|
.attr("y", _yAxisLabelOption.y) |
|
.attr("text-anchor", _yAxisLabelOption["text-anchor"]) |
|
.attr("dominant-baseline", _yAxisLabelOption["dominant-baseline"]) |
|
.attr("transform", "translate("+[_margin.left, _margin.top]+")") |
|
|
|
} |
|
|
|
function renderXAxisLabel() { |
|
var xAxisLabel = axisLayer.selectAll(".label.x") |
|
.data(["dummy"]) |
|
|
|
var newXAxisLabel = xAxisLabel.enter().append("text").attr("class", "label x") |
|
|
|
xAxisLabel.merge(newXAxisLabel) |
|
.text(function(d){ return _xAxisLabel }) |
|
.attr("x", _xAxisLabelOption.x) |
|
.attr("y", _xAxisLabelOption.y) |
|
.attr("text-anchor", _xAxisLabelOption["text-anchor"]) |
|
.attr("dominant-baseline", _xAxisLabelOption["dominant-baseline"]) |
|
.attr("transform", "translate("+[_chartWidth+_margin.left, _chartHeight+_margin.top]+")") |
|
|
|
} |
|
|
|
function renderBarChart(data) { |
|
|
|
var bar = chartLayer.selectAll(".bar").data(data) |
|
|
|
bar.exit().remove() |
|
|
|
var newBar = bar.enter().append("rect") |
|
.attr("class", function(d){ return "bar " + _x(d) }) |
|
|
|
bar.merge(newBar) //選択済みセレクションをenterで追加されるセレクションにマージする |
|
.attr("width", _xScale.bandwidth()) |
|
.attr("height", function(d){ |
|
var height = Math.abs( _yScale(_y(d)) - _yScale(0) ) |
|
return height |
|
}) |
|
.attr("transform", function(d){ |
|
var y = _yScale(Math.max(0, _y(d))) |
|
return "translate("+[_xScale(_x(d)), y]+")" |
|
|
|
}) |
|
|
|
} |
|
|
|
//セレクションにモジュールへのショートカットをつける |
|
_selection._module = exports |
|
|
|
|
|
}) |
|
} |
|
|
|
exports.margin = function(_arg) { |
|
if (!arguments.length) return _margin; |
|
Object.keys(_arg).forEach(function(key){ |
|
_margin[key] = _arg[key] |
|
}) |
|
return this; |
|
} |
|
|
|
exports.x = function(_arg) { |
|
if (!arguments.length) return _x; |
|
_x = _arg; |
|
return this; |
|
} |
|
|
|
exports.y = function(_arg) { |
|
if (!arguments.length) return _y; |
|
_y = _arg; |
|
return this; |
|
} |
|
exports.xScale = function(_arg) { |
|
if (!arguments.length) return _xScale; |
|
_xScale = _arg; |
|
return this; |
|
} |
|
|
|
exports.yScale = function(_arg) { |
|
if (!arguments.length) return _yScale; |
|
_yScale = _arg; |
|
return this; |
|
} |
|
|
|
exports.xScaleDomain = function(_arg) { |
|
if (!arguments.length) return _xScaleDomain; |
|
_xScaleDomain = _arg; |
|
return this; |
|
} |
|
|
|
exports.yScaleDomain = function(_arg) { |
|
if (!arguments.length) return _yScaleDomain; |
|
_yScaleDomain = _arg; |
|
return this; |
|
} |
|
|
|
exports.xScalePaddingInner = function(_arg) { |
|
if (!arguments.length) return _xScalePaddingInner; |
|
_xScalePaddingInner = _arg; |
|
return this; |
|
} |
|
|
|
exports.xScalePaddingOuter = function(_arg) { |
|
if (!arguments.length) return _xScalePaddingOuter; |
|
_xScalePaddingOuter = _arg; |
|
return this; |
|
} |
|
|
|
exports.xTickValues = function(_arg) { |
|
if (!arguments.length) return _xTickValues; |
|
_xTickValues = _arg; |
|
return this; |
|
} |
|
|
|
exports.yTickValues = function(_arg) { |
|
if (!arguments.length) return _yTickValues; |
|
_yTickValues = _arg; |
|
return this; |
|
} |
|
|
|
exports.xAxisGridVisible = function(_arg) { |
|
if (!arguments.length) return _xAxisGridVisible; |
|
_xAxisGridVisible = _arg; |
|
return this; |
|
} |
|
|
|
exports.yAxisGridVisible = function(_arg) { |
|
if (!arguments.length) return _yAxisGridVisible; |
|
_yAxisGridVisible = _arg; |
|
return this; |
|
} |
|
|
|
exports.xAxisLabel = function(_arg) { |
|
if (!arguments.length) return _xAxisLabel; |
|
_xAxisLabel = _arg; |
|
return this; |
|
} |
|
|
|
exports.yAxisLabel = function(_arg) { |
|
if (!arguments.length) return _yAxisLabel; |
|
_yAxisLabel = _arg; |
|
return this; |
|
} |
|
|
|
exports.xAxisLabelOption = function(_arg) { |
|
if (!arguments.length) return _xAxisLabelOption; |
|
Object.keys(_arg).forEach(function(key){ |
|
_xAxisLabelOption[key] = _arg[key] |
|
}) |
|
return this; |
|
} |
|
|
|
exports.yAxisLabelOption = function(_arg) { |
|
if (!arguments.length) return _yAxisLabelOption; |
|
Object.keys(_arg).forEach(function(key){ |
|
_yAxisLabelOption[key] = _arg[key] |
|
}) |
|
return this; |
|
} |
|
|
|
exports.responsive = function(_arg) { |
|
if (!arguments.length) return _responsive; |
|
_responsive = _arg; |
|
return this; |
|
} |
|
|
|
|
|
return exports |
|
} |