Published
Edited
Oct 12, 2020
Fork of D3 Template
5 stars
Also listed in…
Techniques
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function Chart() {
// Exposed variables
var attrs = {
id: 'ID' + Math.floor(Math.random() * 1000000), // Id for event handlings
svgWidth: 400,
svgHeight: 400,
marginTop: 5,
marginBottom: 5,
marginRight: 5,
marginLeft: 5,
container: 'body',
defaultTextFill: '#2C3E50',
defaultFont: 'Helvetica',
data: null,
dropShadowId: DOM.uid().id
};

//InnerFunctions which will update visuals
var updateData;

//Main chart object
var main = function() {
//Drawing containers
var container = d3.select(attrs.container);
var containerRect = container.node().getBoundingClientRect();
if (containerRect.width > 0) attrs.svgWidth = containerRect.width;

//Calculated properties
var calc = {
id:null,
chartTopMargin:null,
chartLeftMargin:null,
chartWidth:null,
chartHeight:null
};
calc.id = 'ID' + Math.floor(Math.random() * 1000000); // id for event handlings
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;
}
Insert cell
d3 = require('d3')
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
import {colorPicker} from "@shaunlebron/color-picker"
Insert cell
import {inputsGroup} from "@bumbeishvili/input-groups"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more