function makeSVGChart(cfg) {
let {xMin=0, xMax=100, xaTop=true, xaMid=true, xaBottom=true, yMin=0, yMax=100, yaLeft=true, yaMid=true, yaRight=true, height=100, width=100, margin={left:50, top:50, right:50, bottom:50}, ticks=10} = cfg;
const w = width - margin.right - margin.left;
const h = height - margin.top - margin.bottom;
const x = d3.scaleLinear().domain([xMin,xMax]).range([0,w]);
const y = d3.scaleLinear().domain([yMin,yMax]).range([h,0]);
let svg = d3.select(DOM.svg(width, height));
if (yaLeft) svg.append("g")
.attr("transform", "translate(" + margin.left + " " + margin.top + ")")
.call(d3.axisLeft(y).ticks(ticks))
.selectAll(".tick line").clone()
.attr("x2", w)
.attr("stroke-opacity", 0.1);
if (yaRight) svg.append("g")
.attr("transform", "translate(" + (width - margin.right) + "," + margin.top + ")")
.call(d3.axisRight(y).ticks(ticks));
if (yaMid) svg.append("g")
.attr("transform", "translate(" + (w/2+margin.left) + "," + margin.top + ")")
.call(d3.axisLeft(y).ticks(ticks));
if (xaBottom) svg.append("g")
.attr("transform", "translate(" + margin.left + " " + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).ticks(ticks));
if (xaTop) svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.bottom + ")")
.call(d3.axisTop(x).ticks(ticks))
.selectAll(".tick line").clone()
.attr("y2", h)
.attr("stroke-opacity", 0.1)
if (xaMid) svg.append("g")
.attr("transform", "translate(" + margin.top + "," + (h/2+margin.top) + ")")
.call(d3.axisTop(x).ticks(ticks));
function xm(d) { return x(d) + margin.left}
function ym(d) { return y(d) + margin.top}
return [svg, xm, ym, x, y];
}