@redsift/d3-rs-svg
Version:
Creates a SVG element using D3v4.
182 lines (146 loc) • 5.06 kB
JavaScript
import { select } from "d3-selection";
export default function svg(id) {
let width = 300,
height = 150,
top = 16,
right = 16,
bottom = 16,
left = 16,
scale = 1,
inner = 'g.svg-child',
innerWidth = -1,
innerHeight = -1,
style = null,
background = null,
title = null,
desc = null,
role = 'img',
classed = 'svg-svg',
overflow = false;
function _updateInnerWidth() {
innerWidth = width - left - right;
}
function _updateInnerHeight() {
innerHeight = height - top - bottom;
}
_updateInnerWidth();
_updateInnerHeight();
function _impl(context) {
let selection = context.selection ? context.selection() : context,
transition = (context.selection !== undefined);
selection.each(function() {
let parent = select(this);
let el = parent.select(_impl.self());
if (el.empty()) {
let ariaTitle = (id == null ? '' : id + '-') + 'title';
let ariaDesc = (id == null ? '' : id + '-') + 'desc';
el = parent.append('svg')
.attr('version', '1.1')
.attr('xmlns', 'http://www.w3.org/2000/svg')
.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink') // d3 work around for xlink not required as per D3 4.0
.attr('preserveAspectRatio', 'xMidYMid meet')
.attr('aria-labelledby', ariaTitle)
.attr('aria-describedby', ariaDesc)
.attr('id', id);
el.append('title').attr('id', ariaTitle);
el.append('desc').attr('id', ariaDesc);
el.append('defs');
el.append('rect').attr('class', 'background');
el.append('g').attr('class', 'svg-child');
}
el.attr('overflow', overflow ? 'visible' : 'hidden');
let defsEl = el.select('defs');
let styleEl = defsEl.selectAll('style').data(style ? [ style ] : []);
styleEl.exit().remove();
styleEl = styleEl.enter().append('style').attr('type', 'text/css').merge(styleEl);
styleEl.text(style);
el.attr('role', role);
el.select('title').text(title);
el.select('desc').text(desc);
let rect = el.select('rect.background')
.attr('width', background != null ? width * scale : null)
.attr('height', background != null ? height * scale : null);
// Never transition
el.attr('class', classed)
let g = el.select(_impl.child());
if (transition === true) {
el = el.transition(context);
g = g.transition(context);
rect = rect.transition(context);
}
// Transition if enabled
el.attr('width', width * scale)
.attr('height', height * scale)
.attr('viewBox', '0 0 ' + width + ' ' + height);
g.attr('transform', 'translate(' + left + ',' + top + ')');
rect.attr('fill', background);
});
}
_impl.self = function() { return 'svg' + (id ? '#' + id : ''); }
_impl.child = function() { return inner; }
_impl.childDefs = function() { return 'defs'; }
_impl.childWidth = function() { return innerWidth; }
_impl.childHeight = function() { return innerHeight; }
_impl.id = function() {
return id;
};
_impl.classed = function(value) {
return arguments.length ? (classed = value, _impl) : classed;
};
_impl.style = function(value) {
return arguments.length ? (style = value, _impl) : style;
};
_impl.background = function(value) {
return arguments.length ? (background = value, _impl) : background;
};
_impl.width = function(value) {
if (!arguments.length) return width;
width = value;
_updateInnerWidth();
return _impl;
};
_impl.height = function(value) {
if (!arguments.length) return width;
height = value;
_updateInnerHeight();
return _impl;
};
_impl.scale = function(value) {
return arguments.length ? (scale = value, _impl) : scale;
};
_impl.title = function(value) {
return arguments.length ? (title = value, _impl) : title;
};
_impl.desc = function(value) {
return arguments.length ? (desc = value, _impl) : desc;
};
_impl.role = function(value) {
return arguments.length ? (role = value, _impl) : role;
};
_impl.overflow = function(value) {
return arguments.length ? (overflow = value, _impl) : overflow;
};
_impl.margin = function(value) {
if (!arguments.length) return {
top: top,
right: right,
bottom: bottom,
left: left
};
if (value.top !== undefined) {
top = value.top;
right = value.right;
bottom = value.bottom;
left = value.left;
} else {
top = value;
right = value;
bottom = value;
left = value;
}
_updateInnerWidth();
_updateInnerHeight();
return _impl;
};
return _impl;
}