/** * * @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 }