proxyを使用しているため、対応しているブラウザ以外では動作しません。
○ Charome, FIrefox
× IE, Safari
Built with blockbuilder.org
| license: mit |
proxyを使用しているため、対応しているブラウザ以外では動作しません。
○ Charome, FIrefox
× IE, Safari
Built with blockbuilder.org
| /** | |
| * | |
| * @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] | |
| } | |
| _xScaleDomain = xMap | |
| _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) }) | |
| .attr("height", 0) | |
| .attr("transform", function(d){ return "translate("+[_xScale(_x(d)), _chartHeight]+")"}) | |
| bar.merge(newBar) | |
| .attr("width", _xScale.bandwidth()) | |
| bar.merge(newBar).transition(_transitionObject) | |
| .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.update = function(data){ | |
| var _data = data | |
| main(_data) | |
| } | |
| _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.responsive = function(_arg) { | |
| if (!arguments.length) return _responsive; | |
| _responsive = _arg; | |
| return this; | |
| } | |
| return exports | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"/> | |
| <title>D3 - use Proxy</title> | |
| <style> | |
| html, body { | |
| width: 100%; | |
| height: 100%; | |
| padding: 0px; | |
| margin: 0px; | |
| } | |
| #chart { | |
| width: 900px; | |
| height: 450px; | |
| } | |
| .vbarChart .bar { | |
| fill:blue; | |
| } | |
| /* axis */ | |
| .vbarChart .axis { | |
| } | |
| .vbarChart .axis .domain { | |
| stroke: #333333; | |
| } | |
| .vbarChart .tick line { | |
| stroke: #333333; | |
| stroke-width: 1px; | |
| } | |
| .vbarChart .tick text { | |
| fill: #333333; | |
| font-size: 14px; | |
| letter-spacing: .05em; | |
| } | |
| /* grid */ | |
| .vbarChart .grid line { | |
| stroke: #cccccc; | |
| stroke-dasharray: 3,3; | |
| } | |
| /* label */ | |
| .vbarChart .label { | |
| font-size: 12px; | |
| font-weight: normal; | |
| letter-spacing: .05em; | |
| } | |
| #form { | |
| margin: 10px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="form"> | |
| tokyo:<input class="input" type="number" name="tokyo"> | |
| gunma:<input class="input" type="number" name="gunma"> | |
| saitama:<input class="input" type="number" name="saitama"> | |
| </div> | |
| <div id="chart"></div> | |
| <script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script> | |
| <script src="createVBarChart.js"></script> | |
| <script> | |
| !(function(){ | |
| "use strict"; | |
| const dataSet = [ | |
| {name:"tokyo", value:"100"}, | |
| {name:"gunma", value:"200"}, | |
| {name:"saitama", value:"300"} | |
| ] | |
| //バーチャートモジュールを生成 | |
| const BarChart = createVBarChart() | |
| .margin({top:40, left:100, bottom:40, right:10}) | |
| .x(function(d){ return d["name"] }) | |
| .y(function(d){ return d["value"] }) | |
| //チャートを描画する | |
| const selector = d3.selectAll("#chart").datum(dataSet) | |
| .call(BarChart) | |
| //データセットの内容が変更されたらチャートをアップデートする | |
| const proxyHandler = { | |
| get: function(target, name, value){ | |
| return target[name] | |
| }, | |
| set: function(target, name, value){ | |
| if (name == "value" && isNaN(+value)) throw new TypeError("型がちがうよ") | |
| target[name] = value | |
| selector.update(dataSet) //チャートアップデート | |
| return target[name] | |
| } | |
| } | |
| //データセットをネストし、proxyで包む | |
| const nested = d3.nest() | |
| .rollup(function(d){ return new Proxy(d[0], proxyHandler) }) | |
| .key(function(d){ return d.name }) | |
| .map(dataSet) | |
| //テキストボックスの値が変更されたらデータセットをporxy経由で変更する | |
| const updateDataset = function() { | |
| nested["$"+this.name].value = this.value | |
| } | |
| const textBox = d3.selectAll(".input") | |
| .on("change", updateDataset) | |
| //テキストボックスに初期値を渡す。 | |
| textBox.each(function(){ | |
| this.value = nested["$"+this.name].value | |
| }) | |
| }()); | |
| </script> | |
| </body> | |
| </html> |