function Chart() {
var attrs = {
id: 'ID' + Math.floor(Math.random() * 1000000),
svgWidth: 400,
svgHeight: 400,
marginTop: 5,
marginBottom: 5,
marginRight: 5,
marginLeft: 5,
container: 'body',
defaultTextFill: '#2C3E50',
defaultFont: 'Helvetica',
data: null,
dropShadowId: DOM.uid().id
};
var updateData;
var main = function() {
var container = d3.select(attrs.container);
var containerRect = container.node().getBoundingClientRect();
if (containerRect.width > 0) attrs.svgWidth = containerRect.width;
var calc = {
id:null,
chartTopMargin:null,
chartLeftMargin:null,
chartWidth:null,
chartHeight:null
};
calc.id = 'ID' + Math.floor(Math.random() * 1000000);
calc.chartLeftMargin = attrs.marginLeft;
calc.chartTopMargin = attrs.marginTop;
calc.chartWidth = attrs.svgWidth - attrs.marginRight - calc.chartLeftMargin;
calc.chartHeight = attrs.svgHeight - attrs.marginBottom - calc.chartTopMargin;
//Add svg
var svg = container
.patternify({ tag: 'svg', selector: 'svg-chart-container' })
.attr('width', attrs.svgWidth)
.attr('height', attrs.svgHeight)
.attr('font-family', attrs.defaultFont);
//Add container g element
var chart = svg
.patternify({ tag: 'g', selector: 'chart' })
.attr('transform', 'translate(' + calc.chartLeftMargin + ',' + calc.chartTopMargin + ')');
// ================= DROP SHADOW PART =================
var defs = svg.patternify({tag:'defs',selector:'defs-element'});
var filter = defs.patternify({tag:'filter',selector:'shadow-filter-element'})
.attr('id', attrs.dropShadowId)
.attr('y',`${filterY}%`)
.attr('x',`${filterX}%`)
.attr('height', `${filterHeight}%`)
.attr('width',`${filterWidth}%`)
filter.patternify({tag:'feGaussianBlur',selector:'feGaussianBlur-element'})
.attr('in', 'SourceAlpha')
.attr('stdDeviation', feGaussianBlurStdDeviation)
.attr('result', 'blur');
filter.patternify({tag:'feOffset',selector:'feOffset-element'})
.attr('in', 'blur')
.attr('result', 'offsetBlur')
.attr("dx", feOffsetDx)
.attr("dy", feOffsetDy)
.attr("x", feOffsetX)
.attr("y", feOffsetY)
filter.patternify({tag:'feFlood',selector:'feFlood-element'})
.attr("in", "offsetBlur")
.attr("flood-color",color)
.attr("flood-opacity", opacity)
.attr("result", "offsetColor");
filter.patternify({tag:'feComposite',selector:'feComposite-element'})
.attr("in", "offsetColor")
.attr("in2", "offsetBlur")
.attr("operator", "in")
.attr("result", "offsetBlur");
var feMerge = filter.patternify({tag:'feMerge',selector:'feMerge-element'})
feMerge.patternify({tag:'feMergeNode',selector:'feMergeNode-blur'})
.attr('in', 'offsetBlur')
feMerge.patternify({tag:'feMergeNode',selector:'feMergeNode-graphic'})
.attr('in', 'SourceGraphic')
chart
.patternify({ tag: 'circle', selector: 'example-text', data: [ attrs.data.message ] })
.attr('cx',100)
.attr('cy',100)
.attr('fill','#FAFAFA')
.attr('r', 40)
.style("filter", `url(#${attrs.dropShadowId})`);
// ================= END OF DROP SHADOW PART =================
// Smoothly handle data updating
updateData = function() {};
//######################################### UTIL FUNCS ##################################
d3.select(window).on('resize.' + attrs.id, function() {
var containerRect = container.node().getBoundingClientRect();
if (containerRect.width > 0) attrs.svgWidth = containerRect.width;
main();
});
};
//----------- PROTOTYPE FUNCTIONS ----------------------
d3.selection.prototype.patternify = function(params) {
var container = this;
var selector = params.selector;
var elementTag = params.tag;
var data = params.data || [ selector ];
// Pattern in action
var selection = container.selectAll('.' + selector).data(data, (d, i) => {
if (typeof d === 'object') {
if (d.id) {
return d.id;
}
}
return i;
});
selection.exit().remove();
selection = selection.enter().append(elementTag).merge(selection);
selection.attr('class', selector);
return selection;
};
//Dynamic keys functions
Object.keys(attrs).forEach((key) => {
// Attach variables to main function
//@ts-ignore
main[key] = function(_) {
var string = `attrs['${key}'] = _`;
if (!arguments.length) {
return eval(` attrs['${key}'];`);
}
eval(string);
return main;
};
return main;
});
//Set attrs as property
//@ts-ignore
main['attrs'] = attrs;
//Exposed update functions
//@ts-ignore
main['data'] = function(value) {
if (!arguments.length) return attrs.data;
attrs.data = value;
if (typeof updateData === 'function') {
updateData();
}
return main;
};
// Run visual
//@ts-ignore
main['render'] = function() {
main();
return main;
};
return main;
}