/** * @module nChart/createAxis * @desc Axis(軸)を生成します。 * @example *var instans = nChart.createAxis() * * *var selector = d3.select(query) * .datum(data) * .call(instans) */ !(function() { "use strict"; if (typeof module !== "undefined" && module.exports) { module.exports = createAxis; } else { window.createAxis = createAxis; } function createAxis() { var _chartWidth, _chartHeight; var _plotWidth, _plotHeight; var _plotMargin = null; //{top:0, left:0, bottom:0, right:0}; var _x = function() { return d; }, _y = function() { return d; }; var _leftAxisFlag = true, _rightAxisFlag = false, _topAxisFlag = false, _bottomAxisFlag = true; var _xTickLabelFlip = false, _yTickLabelFlip = false; var _xScale, _yScale; var _leftTopLabel, _rightTopLabel, _LeftBottomLabel, _rightBottomLabel; var _xAxisGridVisible = false, _yAxisGridVisible = false; var _xAxisDomainLineVisible = true, _yAxisDomainLineVisible = true; var _yTicks, _xTicks; var _yTickValues, _xTickValues; var _yTickPadding, _xTickPadding; var _yTickSizeOuter = 7.5, _xTickSizeOuter = 7.5; var _yTickSize = 8, _xTickSize = 8; var _yTickFormat = function(d) { return d; }, _xTickFormat = function(d) { return d; }; var _responsive = true; function instance(_selection) { _selection.each(function(_data) { if (!_selection._enableBindAxis) throw new Error( "このセレクターにはAxisをバインドすることができません" ); var isHash = function(value) { return value.toString() === "[object Object]"; }; var isArray = Array.isArray || function(value) { return value.toString() === "[object Array]"; }; var _parentNode = _selection.node(); //axisモジュールはすでにセレクター内に以下要素が生成されているのが前提 //parent -> svg element var target = _selection._addSvgElement ? "svg" : "g"; var svg = _selection.selectAll(target); var axisLayer = svg.selectAll(".axisLayer"); var backgroundLayer = svg.selectAll(".backgroundLayer"); var selectedGridLayer = backgroundLayer .selectAll(".gridLayer") .data(["dummy"]); var newGridLayer = selectedGridLayer .enter() .append("g") .attr("class", "gridLayer"); var gridLaye = selectedGridLayer.merge(newGridLayer); main(_data); if (_responsive) setReSizeEvent(); updateBindSelector(_selection); function main(data) { //セレクターにバインドされているアクセサを使用する _x = _selection._x; _y = _selection._y; //セレクターにバインドされているスケールを使用する _xScale = _selection._xScale; _yScale = _selection._yScale; //セレクターにバインドされているマージンを使用する _plotMargin = _selection._plotMargin; setSize(); copyScale(_selection); //グリッドの表示・非表示 if (_yAxisGridVisible) renderYAxisGrid(); if (_xAxisGridVisible) renderXAxisGrid(); //軸の表示・非表示 if (_leftAxisFlag) renderLeftYAxis(); if (_bottomAxisFlag) renderBottomXAxis(); if (_rightAxisFlag) renderRightYAxis(); if (_topAxisFlag) renderTopXAxis(); //ラベルの表示・非表示 if (_leftTopLabel) renderLeftTopLabel(); if (_rightTopLabel) renderRightTopLabel(); if (_LeftBottomLabel) renderLeftBottomLabel(); if (_rightBottomLabel) renderRightBottomLabel(); } //リサイズ時処理 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) { var parentWidth = _parentNode.clientWidth || _parentNode.parentNode.clientWidth; var parentHeight = _parentNode.clientHeight || _parentNode.parentNode.clientHeight; _plotWidth = parentWidth - (_plotMargin.left + _plotMargin.right); _plotHeight = parentHeight - (_plotMargin.top + _plotMargin.bottom); svg.attr("width", parentWidth).attr("height", parentHeight); axisLayer.attr("width", _chartWidth).attr("height", _chartHeight); gridLaye.attr("width", _chartWidth).attr("height", _chartHeight); } //セッションにバインドされたスケールをコピーする function copyScale(_selection) { _xScale = _selection._xScale; _yScale = _selection._yScale; } //チャート右に Y軸を表示 function renderRightYAxis() { var yAxisCall = _yTickLabelFlip ? d3.axisLeft() : d3.axisRight(); yAxisCall .scale(_yScale) .tickSizeOuter(0) .tickSize(_yTickSize) .tickFormat(_yTickFormat) .tickSizeOuter(_yTickSizeOuter); if (_yTicks) yAxisCall.ticks(_yTicks); if (_yTickValues) yAxisCall.tickValues(_yTickValues); if (typeof _yTickPadding == "number") yAxisCall.tickPadding(_yTickPadding); var yAxis = axisLayer.selectAll(".axis.right").data(["dummy"]); var newYAxis = yAxis.enter().append("g"); newYAxis .merge(yAxis) .attr( "transform", "translate(" + [_plotWidth + _plotMargin.left, _plotMargin.top] + ")" ) .attr("class", "axis right y") .call(yAxisCall); if (!_yAxisDomainLineVisible) { newYAxis .merge(yAxis) .selectAll(".domain") .remove(); } else if (!isNaN(_xScale(0))) newYAxis.merge(yAxis).each(function() { d3.select(this) .select(".domain") .attr( "transform", "translate(" + [-(_plotWidth - _xScale(0)), 0] + ")" ); }); } //チャート左にY軸を表示 function renderLeftYAxis() { var yAxisCall = _yTickLabelFlip ? d3.axisRight() : d3.axisLeft(); yAxisCall .scale(_yScale) .tickSizeOuter(0) .tickSize(_yTickSize) .ticks(_yTicks) .tickFormat(_yTickFormat) .tickSizeOuter(_yTickSizeOuter); if (_yTicks) yAxisCall.ticks(_yTicks); if (_yTickValues) yAxisCall.tickValues(_yTickValues); if (_yTickPadding) yAxisCall.tickPadding(_yTickPadding); var yAxis = axisLayer.selectAll(".axis.left").data(["dummy"]); var newYAxis = yAxis.enter().append("g"); newYAxis .merge(yAxis) .transition() .attr( "transform", "translate(" + [_plotMargin.left, _plotMargin.top] + ")" ) .attr("class", "axis left y") .call(yAxisCall); if (!_yAxisDomainLineVisible) { newYAxis .merge(yAxis) .selectAll(".domain") .remove(); } else if (!isNaN(_xScale(0))) newYAxis.merge(yAxis).each(function() { d3.select(this) .select(".domain") .attr("transform", "translate(" + [_xScale(0), 0] + ")"); }); } //チャート上にX軸を表示 function renderTopXAxis() { var xAxisCall = _xTickLabelFlip ? d3.axisBottom() : d3.axisTop(); xAxisCall .scale(_xScale) .tickSizeOuter(0) .tickSize(_xTickSize) .tickFormat(_xTickFormat) .tickSizeOuter(_xTickSizeOuter); if (_xTicks) xAxisCall.ticks(_xTicks); if (_xTickValues) xAxisCall.tickValues(_xTickValues); if (typeof _xTickPadding == "number") xAxisCall.tickPadding(_xTickPadding); var xAxis = axisLayer.selectAll(".axis.top").data(["dummy"]); var newXAxis = xAxis.enter().append("g"); newXAxis .merge(xAxis) .attr( "transform", "translate(" + [_plotMargin.left, _plotMargin.top] + ")" ) .attr("class", "axis top x") .call(xAxisCall); if (!_xAxisDomainLineVisible) { newXAxis .merge(xAxis) .selectAll(".domain") .remove(); } else if (!isNaN(_yScale(0))) newXAxis.merge(xAxis).each(function() { d3.select(this) .select(".domain") .attr( "transform", "translate(" + [0, -(_plotHeight - _yScale(0))] + ")" ); }); } //チャート下にX軸を表示 function renderBottomXAxis() { var xAxisCall = _xTickLabelFlip ? d3.axisTop() : d3.axisBottom(); xAxisCall .scale(_xScale) .tickSizeOuter(0) .tickSize(_xTickSize) .tickFormat(_xTickFormat) .tickSizeOuter(_xTickSizeOuter); if (_xTicks) xAxisCall.ticks(_xTicks); if (_xTickValues) xAxisCall.tickValues(_xTickValues); if (typeof _xTickPadding == "number") xAxisCall.tickPadding(_xTickPadding); var xAxis = axisLayer.selectAll(".axis.bottom").data(["dummy"]); var newXAxis = xAxis.enter().append("g"); newXAxis .merge(xAxis) .attr( "transform", "translate(" + [_plotMargin.left, _plotHeight + _plotMargin.top] + ")" ) .attr("class", "axis bottom x") .call(xAxisCall); if (!_xAxisDomainLineVisible) { newXAxis .merge(xAxis) .selectAll(".domain") .remove(); } else if (!isNaN(_yScale(0))) newXAxis.merge(xAxis).each(function() { d3.select(this) .select(".domain") .attr( "transform", "translate(" + [0, -(_plotHeight - _yScale(0))] + ")" ); }); } //左Y軸にラベルを表示する function renderLeftTopLabel() { var yAxisLabel = axisLayer.selectAll(".leftLabel.y").data(["dummy"]); var newYAxisLabel = yAxisLabel .enter() .append("text") .attr("class", "leftLabel y"); yAxisLabel .merge(newYAxisLabel) .text(function(d) { return _leftTopLabel; }) .attr("x", _plotMargin.left) .attr("y", _plotMargin.top) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle"); } //右Y軸にラベルを表示する function renderRightTopLabel() { var yAxisLabel = axisLayer.selectAll(".rightLabel.y").data(["dummy"]); var newYAxisLabel = yAxisLabel .enter() .append("text") .attr("class", "rightLabel y"); yAxisLabel .merge(newYAxisLabel) .text(function(d) { return _rightTopLabel; }) .attr("x", _plotMargin.left + _plotWidth) .attr("y", _plotMargin.top) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle"); } //下X軸にラベルを表示する function renderRightBottomLabel() { var xAxisLabel = axisLayer.selectAll(".rightLabel.x").data(["dummy"]); var newXAxisLabel = xAxisLabel .enter() .append("text") .attr("class", "rightLabel x"); xAxisLabel .merge(newXAxisLabel) .text(function(d) { return _rightBottomLabel; }) .attr("x", _plotWidth + _plotMargin.left) .attr("y", _plotHeight + _plotMargin.top) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle"); } //下X軸にラベルを表示する function renderLeftBottomLabel() { var xAxisLabel = axisLayer.selectAll(".leftLabel.x").data(["dummy"]); var newXAxisLabel = xAxisLabel .enter() .append("text") .attr("class", "leftLabel x"); xAxisLabel .merge(newXAxisLabel) .text(function(d) { return _LeftBottomLabel; }) .attr("x", _plotMargin.left) .attr("y", _plotHeight + _plotMargin.top) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle"); } // Y軸に横のグリッドを生成する function renderYAxisGrid() { var yAxisCall = d3 .axisLeft(_yScale) .tickSizeOuter(0) .tickSizeInner(-_plotWidth) .tickFormat(function(d) { return null; }); if (_yTicks) yAxisCall.ticks(_yTicks); var yAxis = gridLaye.selectAll(".grid.y").data(["dummy"]); var newYAxis = yAxis .enter() .append("g") .attr("class", "grid y"); newYAxis .merge(yAxis) .attr( "transform", "translate(" + [_plotMargin.left, _plotMargin.top] + ")" ) .call(yAxisCall); //グリッドにdomainのラインは不要なので削除する newYAxis .merge(yAxis) .selectAll(".domain") .remove(); //attributeがstyleより優先されしまうので外す newYAxis .merge(yAxis) .selectAll(".tick line") .attr("stroke", null); } //x軸に縦のグリッドを生成する function renderXAxisGrid() { var xAxisCall = d3 .axisBottom(_xScale) .tickSizeOuter(0) .tickSizeInner(-_plotHeight) .tickFormat(function(d) { return null; }); if (_xTicks) xAxisCall.ticks(_xTicks); var xAxis = gridLaye.selectAll(".grid.x").data(["dummy"]); var newXAxis = xAxis.enter().append("g"); newXAxis .merge(xAxis) .attr( "transform", "translate(" + [_plotMargin.left, _plotHeight + _plotMargin.top] + ")" ) .attr("class", "grid x") .call(xAxisCall); //グリッドにdomainのラインは不要なので削除する newXAxis .merge(xAxis) .selectAll(".domain") .remove(); //attributeがstyleより優先されしまうので外す newXAxis .merge(xAxis) .selectAll(".tick line") .attr("stroke", null); } function updateBindSelector(_selection) { if (!_selection.updateFanctions) _selection.updateFanctions = []; _selection.updateFanctions.push(main); _selection.update = function(data) { _selection.updateFanctions.forEach(function(f) { f(data); }); }; } }); } //getter instance.getChartWidth = function(_arg) { if (!arguments.length) return _plotWidth; throw new Error("このメソッドは取得専用です"); }; instance.getChartHeight = function(_arg) { if (!arguments.length) return _plotHeight; throw new Error("このメソッドは取得専用です"); }; /** * x軸のアウターチックのサイズを指定する * @alias module:nChart/createAxis.xTickSizeOuter * @param {Boolean} flag 反転(true),そのまま(false)を指定する */ instance.xTickSizeOuter = function(_arg) { if (!arguments.length) return _xTickSizeOuter; _xTickSizeOuter = _arg; return this; }; /** * y軸のアウターチックのサイズを指定する * @alias module:nChart/createAxis.yTickSizeOuter * @param {Boolean} flag 反転(true),そのまま(false)を指定する */ instance.yTickSizeOuter = function(_arg) { if (!arguments.length) return _yTickSizeOuter; _yTickSizeOuter = _arg; return this; }; /** * x軸のチックラベルを反転する * @alias module:nChart/createAxis.xTickLabelFlip * @param {Boolean} flag 反転(true),そのまま(false)を指定する */ instance.xTickLabelFlip = function(_arg) { if (!arguments.length) return _xTickLabelFlip; _xTickLabelFlip = _arg; return this; }; /** * y軸のチックラベルを反転する * @alias module:nChart/createAxis.yTickLabelFlip * @param {Boolean} flag 反転(true),そのまま(false)を指定する */ instance.yTickLabelFlip = function(_arg) { if (!arguments.length) return _yTickLabelFlip; _yTickLabelFlip = _arg; return this; }; /** * y軸(左)を表示する * @alias module:nChart/createAxis.leftAxis * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.leftAxis = function(_arg) { if (!arguments.length) return _leftAxisFlag; _leftAxisFlag = _arg; return this; }; /** * y軸(右)を表示する * @alias module:nChart/createAxis.rightAxis * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.rightAxis = function(_arg) { if (!arguments.length) return _rightAxisFlag; _rightAxisFlag = _arg; return this; }; /** * x軸(上)を表示する * @alias module:nChart/createAxis.topAxis * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.topAxis = function(_arg) { if (!arguments.length) return _topAxisFlag; _topAxisFlag = _arg; return this; }; /** * x軸(下)を表示する * @alias module:nChart/createAxis.bottomAxis * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.bottomAxis = function(_arg) { if (!arguments.length) return _bottomAxisFlag; _bottomAxisFlag = _arg; return this; }; /** * x軸のticks数を設定する * @alias module:nChart/createAxis.xTicks * @param {Number} ticks tick数を指定 */ instance.xTicks = function(_arg) { if (!arguments.length) return _xTicks; _xTicks = _arg; return this; }; /** * y軸のticks数を設定する * @alias module:nChart/createAxis.yTicks * @param {Number} ticks tick数を指定 */ instance.yTicks = function(_arg) { if (!arguments.length) return _yTicks; _yTicks = _arg; return this; }; /** * x軸のticksサイズを設定する * @alias module:nChart/createAxis.xTickSize * @param {Number} size tick(ヒゲ)の長さを指定する */ instance.xTickSize = function(_arg) { if (!arguments.length) return _xTickSize; _xTickSize = _arg; return this; }; /** * y軸のticksサイズを設定する * @alias module:nChart/createAxis.yTickSIze * @param {Number} size tick(ヒゲ)の長さを指定する */ instance.yTickSize = function(_arg) { if (!arguments.length) return _yTickSize; _yTickSize = _arg; return this; }; /** * x軸のticks内容を設定する * @alias module:nChart/createAxis.xTickValues * @param {Array} values [index,index,...] tickに表示する項目を渡す */ instance.xTickValues = function(_arg) { if (!arguments.length) return _xTickValues; _xTickValues = _arg; return this; }; /** * y軸のticks内容を設定する * @alias module:nChart/createAxis.yTickValues * @param {Array} values [index,index,...] tickに表示する項目を渡す */ instance.yTickValues = function(_arg) { if (!arguments.length) return _yTickValues; _yTickValues = _arg; return this; }; /** * y軸のチックフォーマットを設定する * @alias module:nChart/createAxis.yTickFormat * @param {Function} fn ラベルとして表示するテキストを渡す */ instance.yTickFormat = function(_arg) { if (!arguments.length) return _yTickFormat; _yTickFormat = _arg; return this; }; /** * x軸のチックフォーマットを設定する * @alias module:nChart/createAxis.xTickFormat * @param {Function} fn ラベルとして表示するテキストを渡す */ instance.xTickFormat = function(_arg) { if (!arguments.length) return _xTickFormat; _xTickFormat = _arg; return this; }; /** * x軸のチックパディングを設定する * @alias module:nChart/createAxis.xTickPadding * @param {Number} ticks tick数を指定 */ instance.xTickPadding = function(_arg) { if (!arguments.length) return _xTickPadding; _xTickPadding = _arg; return this; }; /** * y軸のチックパディングを設定する * @alias module:nChart/createAxis.yTickPadding * @param {Number} ticks tick数を指定 */ instance.yTickPadding = function(_arg) { if (!arguments.length) return _yTickPadding; _yTickPadding = _arg; return this; }; /** * y軸のドメインラインを表示する * @alias module:nChart/createAxis.xAxisDomainLineVisible * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.xAxisDomainLineVisible = function(_arg) { if (!arguments.length) return _xAxisDomainLineVisible; _xAxisDomainLineVisible = _arg; return this; }; /** * x軸のドメインラインを表示する * @alias module:nChart/createAxis.yAxisDomainLineVisible * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.yAxisDomainLineVisible = function(_arg) { if (!arguments.length) return _yAxisDomainLineVisible; _yAxisDomainLineVisible = _arg; return this; }; ///////////////// グリッド ///////////////////////////////////////////////////////////// /** * y軸のグリッドを表示する * @alias module:nChart/createAxis.xAxisGridVisible * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.xAxisGridVisible = function(_arg) { if (!arguments.length) return _xAxisGridVisible; _xAxisGridVisible = _arg; return this; }; /** * x軸のグリッドを表示する * @alias module:nChart/createAxis.yAxisGridVisible * @param {Boolean} flag 表示(true),非表示(false)を渡す */ instance.yAxisGridVisible = function(_arg) { if (!arguments.length) return _yAxisGridVisible; _yAxisGridVisible = _arg; return this; }; ///////////////// ラベル ///////////////////////////////////////////////////////////// /** * 左上のラベル内容を設定する * @alias module:nChart/createAxis.leftTopLabel * @param {String} text ラベルとして表示するテキストを渡す */ instance.leftTopLabel = function(_arg) { if (!arguments.length) return _leftTopLabel; _leftTopLabel = _arg; return this; }; /** * 右上のラベル内容を設定する * @alias module:nChart/createAxis.rightTopLabel * @param {String} text ラベルとして表示するテキストを渡す */ instance.rightTopLabel = function(_arg) { if (!arguments.length) return _rightTopLabel; _rightTopLabel = _arg; return this; }; /** * 左下のラベル内容を設定する * @alias module:nChart/createAxis.leftBottomLabel * @param {String} text ラベルとして表示するテキストを渡す */ instance.leftBottomLabel = function(_arg) { if (!arguments.length) return _LeftBottomLabel; _LeftBottomLabel = _arg; return this; }; /** * レスポンシブ機能の有効・無効を設定する * @param {Boolean} flag 有効, 無効を渡す * @alias module:nChart/createAxis.responsive */ instance.responsive = function(_arg) { if (!arguments.length) return _responsive; _responsive = _arg; return this; }; return instance; } })();