@d3fc/d3fc-axis
Advanced tools
Comparing version 2.1.1 to 2.2.0
@@ -165,2 +165,21 @@ (function (global, factory) { | ||
var regexify = (function (strsOrRegexes) { | ||
return strsOrRegexes.map(function (strOrRegex) { | ||
return typeof strOrRegex === 'string' ? new RegExp('^' + strOrRegex + '$') : strOrRegex; | ||
}); | ||
}); | ||
var exclude = (function () { | ||
for (var _len = arguments.length, exclusions = Array(_len), _key = 0; _key < _len; _key++) { | ||
exclusions[_key] = arguments[_key]; | ||
} | ||
exclusions = regexify(exclusions); | ||
return function (name) { | ||
return exclusions.every(function (exclusion) { | ||
return !exclusion.test(name); | ||
}) && name; | ||
}; | ||
}); | ||
var slicedToArray = function () { | ||
@@ -456,2 +475,6 @@ function sliceIterator(arr, i) { | ||
axis.orient = function () { | ||
return orient; | ||
}; | ||
return axis; | ||
@@ -550,3 +573,3 @@ }; | ||
var axis = function axis(selection) { | ||
return base(selection); | ||
base(selection); | ||
}; | ||
@@ -582,2 +605,187 @@ | ||
var measureLabels = (function (scale) { | ||
var measure = function measure(selection) { | ||
var labels = scale['ticks'] ? scale.ticks() : scale.domain(); | ||
var tester = selection.append('text'); | ||
var boundingBoxes = labels.map(function (l) { | ||
return tester.text(l).node().getBBox(); | ||
}); | ||
var maxHeight = Math.max.apply(Math, toConsumableArray(boundingBoxes.map(function (b) { | ||
return b.height; | ||
}))); | ||
var maxWidth = Math.max.apply(Math, toConsumableArray(boundingBoxes.map(function (b) { | ||
return b.width; | ||
}))); | ||
tester.remove(); | ||
return { | ||
maxHeight: maxHeight, | ||
maxWidth: maxWidth, | ||
labelCount: labels.length | ||
}; | ||
}; | ||
return measure; | ||
}); | ||
var axisLabelRotate = (function (adaptee) { | ||
var labelRotate = 'auto'; | ||
var decorate = function decorate() {}; | ||
var isVertical = function isVertical() { | ||
return adaptee.orient() === 'left' || adaptee.orient() === 'right'; | ||
}; | ||
var sign = function sign() { | ||
return adaptee.orient() === 'top' || adaptee.orient() === 'left' ? -1 : 1; | ||
}; | ||
var labelAnchor = function labelAnchor() { | ||
switch (adaptee.orient()) { | ||
case 'top': | ||
case 'right': | ||
return 'start'; | ||
default: | ||
return 'end'; | ||
} | ||
}; | ||
var calculateRotation = function calculateRotation(s) { | ||
var _measureLabels = measureLabels(adaptee.scale())(s), | ||
maxHeight = _measureLabels.maxHeight, | ||
maxWidth = _measureLabels.maxWidth, | ||
labelCount = _measureLabels.labelCount; | ||
var measuredSize = labelCount * maxWidth; | ||
// The more the overlap, the more we rotate | ||
var rotate = void 0; | ||
if (labelRotate === 'auto') { | ||
var range = adaptee.scale().range()[1]; | ||
rotate = range < measuredSize ? 90 * Math.min(1, (measuredSize / range - 0.8) / 2) : 0; | ||
} else { | ||
rotate = labelRotate; | ||
} | ||
return { | ||
rotate: isVertical() ? Math.floor(sign() * (90 - rotate)) : Math.floor(-rotate), | ||
maxHeight: maxHeight, | ||
maxWidth: maxWidth, | ||
anchor: rotate ? labelAnchor() : 'middle' | ||
}; | ||
}; | ||
var decorateRotation = function decorateRotation(sel) { | ||
var _calculateRotation = calculateRotation(sel), | ||
rotate = _calculateRotation.rotate, | ||
maxHeight = _calculateRotation.maxHeight, | ||
anchor = _calculateRotation.anchor; | ||
var text = sel.select('text'); | ||
var existingTransform = text.attr('transform'); | ||
var offset = sign() * Math.floor(maxHeight / 2); | ||
var offsetTransform = isVertical() ? 'translate(' + offset + ', 0)' : 'translate(0, ' + offset + ')'; | ||
text.style('text-anchor', anchor).attr('transform', existingTransform + ' ' + offsetTransform + ' rotate(' + rotate + ' 0 0)'); | ||
}; | ||
var axisLabelRotate = function axisLabelRotate(arg) { | ||
adaptee(arg); | ||
}; | ||
adaptee.decorate(function (s) { | ||
decorateRotation(s); | ||
decorate(s); | ||
}); | ||
axisLabelRotate.decorate = function () { | ||
if (!arguments.length) { | ||
return decorate; | ||
} | ||
decorate = arguments.length <= 0 ? undefined : arguments[0]; | ||
return axisLabelRotate; | ||
}; | ||
axisLabelRotate.labelRotate = function () { | ||
if (!arguments.length) { | ||
return labelRotate; | ||
} | ||
labelRotate = arguments.length <= 0 ? undefined : arguments[0]; | ||
return axisLabelRotate; | ||
}; | ||
rebindAll(axisLabelRotate, adaptee, exclude('decorate')); | ||
return axisLabelRotate; | ||
}); | ||
var axisLabelOffset = (function (adaptee) { | ||
var labelOffsetDepth = 'auto'; | ||
var decorate = function decorate() {}; | ||
var isVertical = function isVertical() { | ||
return adaptee.orient() === 'left' || adaptee.orient() === 'right'; | ||
}; | ||
var sign = function sign() { | ||
return adaptee.orient() === 'top' || adaptee.orient() === 'left' ? -1 : 1; | ||
}; | ||
var decorateOffset = function decorateOffset(sel) { | ||
var _measureLabels = measureLabels(adaptee.scale())(sel), | ||
maxHeight = _measureLabels.maxHeight, | ||
maxWidth = _measureLabels.maxWidth, | ||
labelCount = _measureLabels.labelCount; | ||
var range = adaptee.scale().range()[1]; | ||
var offsetLevels = labelOffsetDepth === 'auto' ? Math.floor((isVertical() ? maxHeight : maxWidth) * labelCount / range) + 1 : labelOffsetDepth; | ||
var text = sel.select('text'); | ||
var existingTransform = text.attr('transform'); | ||
var transform = function transform(i) { | ||
return isVertical() ? 'translate(' + i % offsetLevels * maxWidth * sign() + ', 0)' : 'translate(0, ' + i % offsetLevels * maxHeight * sign() + ')'; | ||
}; | ||
text.attr('transform', function (_, i) { | ||
return existingTransform + ' ' + transform(i); | ||
}); | ||
}; | ||
var axisLabelOffset = function axisLabelOffset(arg) { | ||
return adaptee(arg); | ||
}; | ||
adaptee.decorate(function (s) { | ||
decorateOffset(s); | ||
decorate(s); | ||
}); | ||
axisLabelOffset.decorate = function () { | ||
if (!arguments.length) { | ||
return decorate; | ||
} | ||
decorate = arguments.length <= 0 ? undefined : arguments[0]; | ||
return axisLabelOffset; | ||
}; | ||
axisLabelOffset.labelOffsetDepth = function () { | ||
if (!arguments.length) { | ||
return labelOffsetDepth; | ||
} | ||
labelOffsetDepth = arguments.length <= 0 ? undefined : arguments[0]; | ||
return axisLabelOffset; | ||
}; | ||
rebindAll(axisLabelOffset, adaptee, exclude('decorate')); | ||
return axisLabelOffset; | ||
}); | ||
exports.axisLabelRotate = axisLabelRotate; | ||
exports.axisLabelOffset = axisLabelOffset; | ||
exports.axisTop = axisTop; | ||
@@ -584,0 +792,0 @@ exports.axisBottom = axisBottom; |
@@ -1,1 +0,1 @@ | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-selection"),require("d3-shape")):"function"==typeof define&&define.amd?define(["exports","d3-selection","d3-shape"],n):n(t.fc=t.fc||{},t.d3,t.d3)}(this,function(t,n,r){"use strict";var e=function(t,n){t=t||"g";var r=function(t,n){return n},e=null,i=function(i,o){o=o||function(t){return t};var u=i.selection?i:null;u&&(i=i.selection());var a=i.selectAll(function(t,n,r){return Array.from(r[n].childNodes).filter(function(t){return 1===t.nodeType})}).filter(null==n?t:t+"."+n),c=a.data(o,r),f=c.enter().append(t).attr("class",n),l=c.exit();c=c.merge(f);var d=u||e;return d&&(c=c.transition(d).style("opacity",1),f.style("opacity",1e-6),l=l.transition(d).style("opacity",1e-6)),l.remove(),c.enter=function(){return f},c.exit=function(){return l},c};return i.element=function(){return arguments.length?(t=arguments.length<=0?void 0:arguments[0],i):t},i.className=function(){return arguments.length?(n=arguments.length<=0?void 0:arguments[0],i):n},i.key=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],i):r},i.transition=function(){return arguments.length?(e=arguments.length<=0?void 0:arguments[0],i):e},i},i=function(t,n,r){var e=n[r];if("function"!=typeof e)throw new Error("Attempt to rebind "+r+" which isn't a function on the source object");return function(){for(var r=arguments.length,i=Array(r),o=0;o<r;o++)i[o]=arguments[o];var u=e.apply(n,i);return u===n?t:u}},o=function(t){return function(n){return t.reduce(function(t,n){return t&&n(t)},n)}},u=function(t,n){for(var r=arguments.length,e=Array(r>2?r-2:0),u=2;u<r;u++)e[u-2]=arguments[u];var a=o(e),c=!0,f=!1,l=void 0;try{for(var d,s=Object.keys(n)[Symbol.iterator]();!(c=(d=s.next()).done);c=!0){var h=d.value,g=a(h);g&&(t[g]=i(t,n,h))}}catch(t){f=!0,l=t}finally{try{!c&&s.return&&s.return()}finally{if(f)throw l}}return t},a=function(){function t(t,n){var r=[],e=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(e=(u=a.next()).done)&&(r.push(u.value),!n||r.length!==n);e=!0);}catch(t){i=!0,o=t}finally{try{!e&&a.return&&a.return()}finally{if(i)throw o}}return r}return function(n,r){if(Array.isArray(n))return n;if(Symbol.iterator in Object(n))return t(n,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),c=function(t){if(Array.isArray(t)){for(var n=0,r=Array(t.length);n<t.length;n++)r[n]=t[n];return r}return Array.from(t)},f=function(t){return t},l=function(t,i){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},u=[10],l=null,d=function(){},s=null,h=6,g=6,v=3,p=r.line(),y=e("g","tick").key(f),m=e("path","domain"),b=function(){return{offset:[0,g+v]}},k=function(){return{path:[[0,0],[0,g]]}},x=o.labelOffset||b,_=o.tickPath||k,A=function(t,n){var r=0;return t.bandwidth&&(r=t.bandwidth()/2,t.round()&&(r=Math.round(r))),function(e){return n(t(e)+r,0)}},O=function(t,n){return S()?"translate("+n+", "+t+")":"translate("+t+", "+n+")"},w=function(t){return S()?t.map(function(t){return[t[1],t[0]]}):t},S=function(){return"left"===t||"right"===t},P=function(t,n,r){return i[t]?i[t].apply(i,n):r},z=function(r){r.selection&&(y.transition(r),m.transition(r)),r.each(function(r,e,o){var g=o[e],v=n.select(g);g.__scale__||v.attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor","right"===t?"start":"left"===t?"end":"middle");var b=g.__scale__||i;g.__scale__=i.copy();var k=null==l?P("ticks",u,i.domain()):l,z=null==s?P("tickFormat",u,f):s,j="bottom"===t||"right"===t?1:-1,N=function(t){var n=a(t,2),r=n[0],e=n[1];return[r,j*e]},I=i.range(),T=w([[I[0],j*h],[I[0],0],[I[1],0],[I[1],j*h]]);m(v,[r]).attr("d",p(T)).attr("stroke","#000");var L=y(v,k),q=k.map(function(t,n){return x(t,n,k)}),B=k.map(function(t,n){return _(t,n,k)});L.enter().attr("transform",A(b,O)).append("path").attr("stroke","#000"),L.enter().append("text").attr("transform",function(t,n){return O.apply(void 0,c(N(q[n].offset)))}).attr("fill","#000"),L.exit().attr("transform",A(i,O)),L.select("path").attr("visibility",function(t,n){return B[n].hidden&&"hidden"}).attr("d",function(t,n){return p(w(B[n].path.map(N)))}),L.select("text").attr("visibility",function(t,n){return q[n].hidden&&"hidden"}).attr("transform",function(t,n){return O.apply(void 0,c(N(q[n].offset)))}).attr("dy",function(){var n="0em";return S()?n="0.32em":"bottom"===t&&(n="0.71em"),n}).text(z),L.attr("transform",A(i,O)),d(L,r,e)})};return z.tickFormat=function(){return arguments.length?(s=arguments.length<=0?void 0:arguments[0],z):s},z.tickSize=function(){return arguments.length?(g=h=Number(arguments.length<=0?void 0:arguments[0]),z):g},z.tickSizeInner=function(){return arguments.length?(g=Number(arguments.length<=0?void 0:arguments[0]),z):g},z.tickSizeOuter=function(){return arguments.length?(h=Number(arguments.length<=0?void 0:arguments[0]),z):h},z.tickPadding=function(){return arguments.length?(v=arguments.length<=0?void 0:arguments[0],z):v},z.decorate=function(){return arguments.length?(d=arguments.length<=0?void 0:arguments[0],z):d},z.scale=function(){return arguments.length?(i=arguments.length<=0?void 0:arguments[0],z):i},z.ticks=function(){for(var t=arguments.length,n=Array(t),r=0;r<t;r++)n[r]=arguments[r];return u=[].concat(n),z},z.tickArguments=function(){return arguments.length?(u=null==(arguments.length<=0?void 0:arguments[0])?[]:[].concat(c(arguments.length<=0?void 0:arguments[0])),z):u.slice()},z.tickValues=function(){return arguments.length?(l=null==(arguments.length<=0?void 0:arguments[0])?[]:[].concat(c(arguments.length<=0?void 0:arguments[0])),z):l.slice()},z},d=function(t,n){var r=!1,e=function(t,e,o){var u=0,a=i.tickSizeInner()+i.tickPadding(),c=!1;if(r){var f=n(t),l=e<o.length-1?n(o[e+1]):n.range()[1];u=(l-f)/2,a=i.tickPadding(),c=e===o.length-1&&f===l}return{offset:[u,a],hidden:c}},i=l(t,n,{labelOffset:e}),o=function(t){return i(t)};return o.tickCenterLabel=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],o):r},u(o,i),o},s=function(t){return d("top",t)},h=function(t){return d("bottom",t)},g=function(t){return d("left",t)},v=function(t){return d("right",t)},p=function(t,n){var r=null,e=function(t,r,e){if(n.step)return n.step();var i=n(t);return r<e.length-1?n(e[r+1])/i:2*(n.range()[1]-i)},i=function(t,n,i){var o=0;return o=r?r(t,n):e(t,n,i)/2,{path:[[o,0],[o,a.tickSizeInner()]],hidden:n===i.length-1}},o=function(){return{offset:[0,a.tickPadding()]}},a=l(t,n,{labelOffset:o,tickPath:i}),c=function(t){return a(t)};return c.tickOffset=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],c):r},u(c,a),c},y=function(t){return p("top",t)},m=function(t){return p("bottom",t)},b=function(t){return p("left",t)},k=function(t){return p("right",t)};t.axisTop=s,t.axisBottom=h,t.axisLeft=g,t.axisRight=v,t.axisOrdinalTop=y,t.axisOrdinalBottom=m,t.axisOrdinalLeft=b,t.axisOrdinalRight=k,Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-selection"),require("d3-shape")):"function"==typeof define&&define.amd?define(["exports","d3-selection","d3-shape"],n):n(t.fc=t.fc||{},t.d3,t.d3)}(this,function(t,n,r){"use strict";var e=function(t,n){t=t||"g";var r=function(t,n){return n},e=null,i=function(i,o){o=o||function(t){return t};var u=i.selection?i:null;u&&(i=i.selection());var a=i.selectAll(function(t,n,r){return Array.from(r[n].childNodes).filter(function(t){return 1===t.nodeType})}).filter(null==n?t:t+"."+n),c=a.data(o,r),f=c.enter().append(t).attr("class",n),l=c.exit();c=c.merge(f);var h=u||e;return h&&(c=c.transition(h).style("opacity",1),f.style("opacity",1e-6),l=l.transition(h).style("opacity",1e-6)),l.remove(),c.enter=function(){return f},c.exit=function(){return l},c};return i.element=function(){return arguments.length?(t=arguments.length<=0?void 0:arguments[0],i):t},i.className=function(){return arguments.length?(n=arguments.length<=0?void 0:arguments[0],i):n},i.key=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],i):r},i.transition=function(){return arguments.length?(e=arguments.length<=0?void 0:arguments[0],i):e},i},i=function(t,n,r){var e=n[r];if("function"!=typeof e)throw new Error("Attempt to rebind "+r+" which isn't a function on the source object");return function(){for(var r=arguments.length,i=Array(r),o=0;o<r;o++)i[o]=arguments[o];var u=e.apply(n,i);return u===n?t:u}},o=function(t){return function(n){return t.reduce(function(t,n){return t&&n(t)},n)}},u=function(t,n){for(var r=arguments.length,e=Array(r>2?r-2:0),u=2;u<r;u++)e[u-2]=arguments[u];var a=o(e),c=!0,f=!1,l=void 0;try{for(var h,d=Object.keys(n)[Symbol.iterator]();!(c=(h=d.next()).done);c=!0){var s=h.value,g=a(s);g&&(t[g]=i(t,n,s))}}catch(t){f=!0,l=t}finally{try{!c&&d.return&&d.return()}finally{if(f)throw l}}return t},a=function(t){return t.map(function(t){return"string"==typeof t?new RegExp("^"+t+"$"):t})},c=function(){for(var t=arguments.length,n=Array(t),r=0;r<t;r++)n[r]=arguments[r];return n=a(n),function(t){return n.every(function(n){return!n.test(t)})&&t}},f=function(){function t(t,n){var r=[],e=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(e=(u=a.next()).done)&&(r.push(u.value),!n||r.length!==n);e=!0);}catch(t){i=!0,o=t}finally{try{!e&&a.return&&a.return()}finally{if(i)throw o}}return r}return function(n,r){if(Array.isArray(n))return n;if(Symbol.iterator in Object(n))return t(n,r);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),l=function(t){if(Array.isArray(t)){for(var n=0,r=Array(t.length);n<t.length;n++)r[n]=t[n];return r}return Array.from(t)},h=function(t){return t},d=function(t,i){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},u=[10],a=null,c=function(){},d=null,s=6,g=6,v=3,p=r.line(),m=e("g","tick").key(h),y=e("path","domain"),x=function(){return{offset:[0,g+v]}},b=function(){return{path:[[0,0],[0,g]]}},k=o.labelOffset||x,A=o.tickPath||b,O=function(t,n){var r=0;return t.bandwidth&&(r=t.bandwidth()/2,t.round()&&(r=Math.round(r))),function(e){return n(t(e)+r,0)}},_=function(t,n){return M()?"translate("+n+", "+t+")":"translate("+t+", "+n+")"},w=function(t){return M()?t.map(function(t){return[t[1],t[0]]}):t},M=function(){return"left"===t||"right"===t},S=function(t,n,r){return i[t]?i[t].apply(i,n):r},P=function(r){r.selection&&(m.transition(r),y.transition(r)),r.each(function(r,e,o){var g=o[e],v=n.select(g);g.__scale__||v.attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor","right"===t?"start":"left"===t?"end":"middle");var x=g.__scale__||i;g.__scale__=i.copy();var b=null==a?S("ticks",u,i.domain()):a,P=null==d?S("tickFormat",u,h):d,z="bottom"===t||"right"===t?1:-1,j=function(t){var n=f(t,2),r=n[0],e=n[1];return[r,z*e]},H=i.range(),L=w([[H[0],z*s],[H[0],0],[H[1],0],[H[1],z*s]]);y(v,[r]).attr("d",p(L)).attr("stroke","#000");var N=m(v,b),R=b.map(function(t,n){return k(t,n,b)}),B=b.map(function(t,n){return A(t,n,b)});N.enter().attr("transform",O(x,_)).append("path").attr("stroke","#000"),N.enter().append("text").attr("transform",function(t,n){return _.apply(void 0,l(j(R[n].offset)))}).attr("fill","#000"),N.exit().attr("transform",O(i,_)),N.select("path").attr("visibility",function(t,n){return B[n].hidden&&"hidden"}).attr("d",function(t,n){return p(w(B[n].path.map(j)))}),N.select("text").attr("visibility",function(t,n){return R[n].hidden&&"hidden"}).attr("transform",function(t,n){return _.apply(void 0,l(j(R[n].offset)))}).attr("dy",function(){var n="0em";return M()?n="0.32em":"bottom"===t&&(n="0.71em"),n}).text(P),N.attr("transform",O(i,_)),c(N,r,e)})};return P.tickFormat=function(){return arguments.length?(d=arguments.length<=0?void 0:arguments[0],P):d},P.tickSize=function(){return arguments.length?(g=s=Number(arguments.length<=0?void 0:arguments[0]),P):g},P.tickSizeInner=function(){return arguments.length?(g=Number(arguments.length<=0?void 0:arguments[0]),P):g},P.tickSizeOuter=function(){return arguments.length?(s=Number(arguments.length<=0?void 0:arguments[0]),P):s},P.tickPadding=function(){return arguments.length?(v=arguments.length<=0?void 0:arguments[0],P):v},P.decorate=function(){return arguments.length?(c=arguments.length<=0?void 0:arguments[0],P):c},P.scale=function(){return arguments.length?(i=arguments.length<=0?void 0:arguments[0],P):i},P.ticks=function(){for(var t=arguments.length,n=Array(t),r=0;r<t;r++)n[r]=arguments[r];return u=[].concat(n),P},P.tickArguments=function(){return arguments.length?(u=null==(arguments.length<=0?void 0:arguments[0])?[]:[].concat(l(arguments.length<=0?void 0:arguments[0])),P):u.slice()},P.tickValues=function(){return arguments.length?(a=null==(arguments.length<=0?void 0:arguments[0])?[]:[].concat(l(arguments.length<=0?void 0:arguments[0])),P):a.slice()},P.orient=function(){return t},P},s=function(t,n){var r=!1,e=function(t,e,o){var u=0,a=i.tickSizeInner()+i.tickPadding(),c=!1;if(r){var f=n(t),l=e<o.length-1?n(o[e+1]):n.range()[1];u=(l-f)/2,a=i.tickPadding(),c=e===o.length-1&&f===l}return{offset:[u,a],hidden:c}},i=d(t,n,{labelOffset:e}),o=function(t){return i(t)};return o.tickCenterLabel=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],o):r},u(o,i),o},g=function(t){return s("top",t)},v=function(t){return s("bottom",t)},p=function(t){return s("left",t)},m=function(t){return s("right",t)},y=function(t,n){var r=null,e=function(t,r,e){if(n.step)return n.step();var i=n(t);return r<e.length-1?n(e[r+1])/i:2*(n.range()[1]-i)},i=function(t,n,i){var o=0;return o=r?r(t,n):e(t,n,i)/2,{path:[[o,0],[o,a.tickSizeInner()]],hidden:n===i.length-1}},o=function(){return{offset:[0,a.tickPadding()]}},a=d(t,n,{labelOffset:o,tickPath:i}),c=function(t){a(t)};return c.tickOffset=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],c):r},u(c,a),c},x=function(t){return y("top",t)},b=function(t){return y("bottom",t)},k=function(t){return y("left",t)},A=function(t){return y("right",t)},O=function(t){return function(n){var r=t.ticks?t.ticks():t.domain(),e=n.append("text"),i=r.map(function(t){return e.text(t).node().getBBox()}),o=Math.max.apply(Math,l(i.map(function(t){return t.height}))),u=Math.max.apply(Math,l(i.map(function(t){return t.width})));return e.remove(),{maxHeight:o,maxWidth:u,labelCount:r.length}}},_=function(t){var n="auto",r=function(){},e=function(){return"left"===t.orient()||"right"===t.orient()},i=function(){return"top"===t.orient()||"left"===t.orient()?-1:1},o=function(){switch(t.orient()){case"top":case"right":return"start";default:return"end"}},a=function(r){var u=O(t.scale())(r),a=u.maxHeight,c=u.maxWidth,f=u.labelCount,l=f*c,h=void 0;if("auto"===n){var d=t.scale().range()[1];h=d<l?90*Math.min(1,(l/d-.8)/2):0}else h=n;return{rotate:e()?Math.floor(i()*(90-h)):Math.floor(-h),maxHeight:a,maxWidth:c,anchor:h?o():"middle"}},f=function(t){var n=a(t),r=n.rotate,o=n.maxHeight,u=n.anchor,c=t.select("text"),f=c.attr("transform"),l=i()*Math.floor(o/2),h=e()?"translate("+l+", 0)":"translate(0, "+l+")";c.style("text-anchor",u).attr("transform",f+" "+h+" rotate("+r+" 0 0)")},l=function(n){t(n)};return t.decorate(function(t){f(t),r(t)}),l.decorate=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],l):r},l.labelRotate=function(){return arguments.length?(n=arguments.length<=0?void 0:arguments[0],l):n},u(l,t,c("decorate")),l},w=function(t){var n="auto",r=function(){},e=function(){return"left"===t.orient()||"right"===t.orient()},i=function(){return"top"===t.orient()||"left"===t.orient()?-1:1},o=function(r){var o=O(t.scale())(r),u=o.maxHeight,a=o.maxWidth,c=o.labelCount,f=t.scale().range()[1],l="auto"===n?Math.floor((e()?u:a)*c/f)+1:n,h=r.select("text"),d=h.attr("transform"),s=function(t){return e()?"translate("+t%l*a*i()+", 0)":"translate(0, "+t%l*u*i()+")"};h.attr("transform",function(t,n){return d+" "+s(n)})},a=function(n){return t(n)};return t.decorate(function(t){o(t),r(t)}),a.decorate=function(){return arguments.length?(r=arguments.length<=0?void 0:arguments[0],a):r},a.labelOffsetDepth=function(){return arguments.length?(n=arguments.length<=0?void 0:arguments[0],a):n},u(a,t,c("decorate")),a};t.axisLabelRotate=_,t.axisLabelOffset=w,t.axisTop=g,t.axisBottom=v,t.axisLeft=p,t.axisRight=m,t.axisOrdinalTop=x,t.axisOrdinalBottom=b,t.axisOrdinalLeft=k,t.axisOrdinalRight=A,Object.defineProperty(t,"__esModule",{value:!0})}); |
@@ -6,2 +6,13 @@ # Change Log | ||
<a name="2.2.0"></a> | ||
# [2.2.0](https://github.com/d3fc/d3fc/compare/@d3fc/d3fc-axis@2.1.1...@d3fc/d3fc-axis@2.2.0) (2019-05-06) | ||
### Features | ||
* Axis decorators for rotated and offset labels ([4f91173](https://github.com/d3fc/d3fc/commit/4f91173)) | ||
<a name="2.1.1"></a> | ||
@@ -8,0 +19,0 @@ ## [2.1.1](https://github.com/d3fc/d3fc/compare/@d3fc/d3fc-axis@2.1.0...@d3fc/d3fc-axis@2.1.1) (2019-03-20) |
var width = 400; | ||
var height = 80; | ||
var margin = 10; | ||
var scale = d3.scaleBand() | ||
.domain(['Carrots', 'Bananas', 'Sausages', 'Pickles', 'Aubergines', 'Artichokes', 'Spinach', 'Cucumber']) | ||
.range([margin, width - 40 - margin]); | ||
var foodScale = d3.scaleBand() | ||
.domain(['Carrots', 'Bananas', 'Sausages', 'Pickles', 'Aubergines', 'Artichokes', 'Spinach', 'Cucumber']) | ||
.range([margin, width - 40 - margin]); | ||
var axis = fc.axisBottom(scale) | ||
.decorate(function(s) { | ||
s.enter().select('text') | ||
.style('text-anchor', 'start') | ||
.attr('transform', 'rotate(45 -10 10)'); | ||
}); | ||
// Decorate | ||
var svg = d3.select('body').append('svg') | ||
.attr('width', width) | ||
.attr('height', 80); | ||
var axis = fc.axisBottom(foodScale) | ||
.decorate(function(s) { | ||
s.enter().select('text') | ||
.style('text-anchor', 'start') | ||
.attr('transform', 'rotate(45 -10 10)'); | ||
}); | ||
var svg = d3.select('#decorateRotate').attr('width', width).attr('height', height); | ||
svg.append('g') | ||
.attr('transform', 'translate(0, 10)') | ||
.call(axis); | ||
// Auto | ||
const draw = () => { | ||
const groupRect = d3.select('.ordinal-group').node().getBoundingClientRect(); | ||
const groupSize = { | ||
width: Math.max(50, groupRect.width - 2 * height), | ||
height: Math.max(50, groupRect.height - 2 * height) | ||
}; | ||
const renderAxis = (target, axis) => { | ||
const side = target.attr('class'); | ||
const vertical = side === 'left' || side === 'right'; | ||
foodScale.range([0, vertical ? groupSize.height : groupSize.width]); | ||
target | ||
.attr('width', `${vertical ? height : groupSize.width}px`) | ||
.attr('height', `${vertical ? groupSize.height : height}px`); | ||
let axisElement = target.select('g'); | ||
if (!axisElement.size()) axisElement = target.append('g'); | ||
axisElement | ||
.attr('transform', () => { | ||
if (side === 'top') return `translate(0, ${height})`; | ||
if (side === 'left') return `translate(${height}, 0)`; | ||
}) | ||
.call(axis); | ||
}; | ||
renderAxis(d3.select('#topAuto'), | ||
fc.axisLabelRotate(fc.axisOrdinalTop(foodScale)) | ||
); | ||
renderAxis(d3.select('#bottomAuto'), | ||
fc.axisLabelRotate(fc.axisOrdinalBottom(foodScale)) | ||
); | ||
renderAxis(d3.select('#leftAuto'), | ||
fc.axisLabelRotate(fc.axisOrdinalLeft(foodScale)) | ||
); | ||
renderAxis(d3.select('#rightAuto'), | ||
fc.axisLabelRotate(fc.axisOrdinalRight(foodScale)) | ||
); | ||
renderAxis(d3.select('#topFixed'), | ||
fc.axisLabelRotate(fc.axisOrdinalTop(foodScale)).labelRotate(30) | ||
); | ||
renderAxis(d3.select('#bottomFixed'), | ||
fc.axisLabelRotate(fc.axisOrdinalBottom(foodScale)).labelRotate(30) | ||
); | ||
renderAxis(d3.select('#leftFixed'), | ||
fc.axisLabelRotate(fc.axisOrdinalLeft(foodScale)).labelRotate(30) | ||
); | ||
renderAxis(d3.select('#rightFixed'), | ||
fc.axisLabelRotate(fc.axisOrdinalRight(foodScale)).labelRotate(30) | ||
); | ||
}; | ||
draw(); | ||
window.addEventListener('resize', () => draw()); |
export * from './src/axis'; | ||
export * from './src/axisOrdinal'; | ||
export { default as axisLabelRotate } from './src/axisLabelRotate'; | ||
export { default as axisLabelOffset } from './src/axisLabelOffset'; |
{ | ||
"name": "@d3fc/d3fc-axis", | ||
"version": "2.1.1", | ||
"version": "2.2.0", | ||
"description": "A drop-in replacement for d3 axis, with support for the d3fc decorate pattern", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
110
README.md
# d3fc-axis | ||
A drop-in replacement for d3 axis, with support for the d3fc decorate pattern, and improved layout options for ordinal scales. | ||
A drop-in replacement for d3 axis, with support for the d3fc decorate pattern, improved layout options for ordinal scales, and automatic label rotation / re-positioning. | ||
@@ -15,7 +15,9 @@ [Main d3fc package](https://github.com/d3fc/d3fc) | ||
### General API | ||
This is a drop-in replacement for [d3-axis](https://github.com/d3/d3-axis), so please refer to that project for detailed documentation - all of the d3-axis properties and features are supported by this component. A few additional properties have been added, which are documented below. | ||
## Tick and label layout options | ||
#### Tick and label layout options | ||
### Centred labels | ||
#### Centred labels | ||
@@ -40,3 +42,3 @@ When rendering an axis that is associated with a linear scale, the default behaviour for the axis is to render labels underneath each tick. This often makes the most sense, with the label indicating a specific instance on the scale. | ||
### Band scales | ||
##### Band scales | ||
@@ -71,45 +73,37 @@ Band scales are often used for rendering charts with a categorical dimension. With the d3 axis, the ticks and labels are rendered at the central point of each bar / column. However, it can make more sense to render the ticks at the boundary between each bar / category. | ||
#### Label rotation / offset | ||
## Decorate pattern | ||
With the D3 axis, if tick marks are too close together, their associated labels might overlap. With d3fc you can apply an adapter to the axis in order to automatically move / rotate labels in order to avoid collisions. | ||
Components that implement the decorate pattern expose a `decorate` property which is passed the data join selection used to construct the component's DOM. This allows users of the component to add extra logic to the enter, update and exit selections. | ||
Here's a simple example where the axis labels overlap: | ||
For further details, consult the [Decorate Pattern documentation](https://d3fc.io/introduction/decorate-pattern.html). | ||
``` | ||
const foodScale = d3.scaleBand() | ||
.domain(['Carrots', 'Bananas', 'Sausages', 'Pickles', 'Aubergines', 'Artichokes', 'Spinach', 'Cucumber']) | ||
.range([10, 290]); | ||
### Examples | ||
const axis = fc.axisOrdinalBottom(foodScale); | ||
The decorate pattern can be used to rotate the tick labels: | ||
d3.select('svg') | ||
.call(axis); | ||
``` | ||
const scale = d3.scaleBand() | ||
.domain(['Carrots', 'Bananas', 'Sausages', 'Pickles', 'Aubergines', 'Artichokes', 'Spinach', 'Cucumber']) | ||
.range([0, 400]); | ||
const axis = fc.axisBottom(scale) | ||
.decorate(s => | ||
s.enter().select('text') | ||
.style('text-anchor', 'start') | ||
.attr('transform', 'rotate(45 -10 10)') | ||
); | ||
<img src="screenshots/overlap.png"/> | ||
The overlap can be avoided by applying one of the adapters, for example you can apply the `axisLabelRotate` adapter as follows: | ||
``` | ||
const axis = fc.axisLabelRotate(fc.axisOrdinalBottom(foodScale)); | ||
``` | ||
Each time the axis is rendered this adapter measures the labels and determines whether they need to be rotated in order to avoid collisions. With this example the axis renders as follows: | ||
<img src="screenshots/rotate.png"/> | ||
Or alternatively the tick index can be used to offset alternating labels: | ||
#### Decorate pattern | ||
``` | ||
const scale = d3.scaleBand() | ||
.domain(['Carrots', 'Bananas', 'Sausages', 'Pickles', 'Aubergines', 'Artichokes', 'Spinach', 'Cucumber']) | ||
.range([0, 400]); | ||
Components that implement the decorate pattern expose a `decorate` property which is passed the data join selection used to construct the component's DOM. This allows users of the component to add extra logic to the enter, update and exit selections. | ||
const axis = fc.axisBottom(scale) | ||
.decorate(s => | ||
s.enter() | ||
.select('text') | ||
.style('transform', (d, i) => i % 2 === 0 ? 'translate(0 20)' : ''); | ||
); | ||
``` | ||
For further details, consult the [Decorate Pattern documentation](https://d3fc.io/introduction/decorate-pattern.html). | ||
<img src="screenshots/offset.png"/> | ||
In the example below, the value bound to each tick is used to colour values greater than or equal to 100: | ||
@@ -134,1 +128,51 @@ | ||
<img src="screenshots/color.png"/> | ||
### Axis | ||
![](screenshots/axis.png) | ||
<a name="axisBottom" href="#axisBottom">#</a> fc.**axisBottom**() | ||
<a name="axisTop" href="#axisTop">#</a> fc.**axisTop**() | ||
<a name="axisLeft" href="#axisLeft">#</a> fc.**axisLeft**() | ||
<a name="axisRight" href="#axisRight">#</a> fc.**axisRight**() | ||
A drop-in replacement for D3 axis, see the [D3 documentation for API reference](https://github.com/d3/d3-axis#api-reference). | ||
### Ordinal Axis | ||
![](screenshots/ordinal.png) | ||
<a name="axisOrdinalBottom" href="#axisOrdinalBottom">#</a> fc.**axisOrdinalBottom**() | ||
<a name="axisOrdinalTop" href="#axisOrdinalTop">#</a> fc.**axisOrdinalTop**() | ||
<a name="axisOrdinalLeft" href="#axisOrdinalLeft">#</a> fc.**axisOrdinalLeft**() | ||
<a name="axisOrdinalRight" href="#axisOrdinalRight">#</a> fc.**axisOrdinalRight**() | ||
A drop-in replacement for D3 axis, see the [D3 documentation for API reference](https://github.com/d3/d3-axis#api-reference). | ||
### Axis Label Offset | ||
![](screenshots/offset.png) | ||
<a name="axisLabelOffset" href="#axisLabelOffset">#</a> fc.**axisLabelOffset**(*axis*) | ||
An adapter that offsets axis labels in order to avoid collisions. | ||
<a name="axisLabelOffset_labelOffsetDepth" href="#axisLabelOffset_labelOffsetDepth">#</a> *axis*.**labelOffsetDepth**(*offset*) | ||
If *offset* is specified, sets the offset depth and returns this series. If *offset* is not specified, returns the current offset depth. | ||
If *offset* is set to `auto`, the adapter will determine the required offset depth (i.e. number of levels) that labels need to be offset by in order to avoid collisions. If *offset* is set to a number, it will offset labels by the given depth. | ||
### Axis Label Rotate | ||
<img src="screenshots/rotate.png" style="width:400px;"/> | ||
<a name="axisLabelRotate" href="#axisLabelRotate">#</a> fc.**axisLabelRotate**(*axis*) | ||
An adapter that rotates axis labels in order to avoid collisions. | ||
<a name="axisLabelRotate_labelRotate" href="#axisLabelRotate_labelRotate">#</a> *axis*.**labelRotate**(*degrees*) | ||
If *degrees* is specified, sets the rotation angle in degrees. If *degrees* is not specified, returns the current rotation angle. | ||
If *degrees* is set to `auto`, the adapter will determine whether the labels will overlap then rotate them to avoid collisions. Depending on the available space, the angle will vary from fairly shallow, all the way up to 90 degrees. If *degrees* is set to a number, it will rotate labels by the given angle. |
@@ -226,3 +226,5 @@ import { select } from 'd3-selection'; | ||
axis.orient = () => orient; | ||
return axis; | ||
}; |
@@ -43,3 +43,3 @@ import { dataJoin as _dataJoin } from '@d3fc/d3fc-data-join'; | ||
const axis = (selection) => { | ||
return base(selection); | ||
base(selection); | ||
}; | ||
@@ -46,0 +46,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
148274
42
1386
175