chart = {
const color = d3.scaleOrdinal(d3.schemeCategory10);
const svg = d3.create("svg").attr("width", 1000).attr("height", 400);
const data = d3.range(100).map(i => ({x:Math.random() * 380, y:Math.random() * 380, id: i, label: Math.round(Math.random() * 10)}));
svg.append('rect').attr('width', 400).attr('height', 400).attr('fill', 'none').attr('stroke', 'black').attr('stroke-width', 1);
const scatter_g = svg.append('g').classed('scatterplot', true).attr('transform', 'translate(10,10)');
scatter_g.append('rect').attr('width', 380).attr('height', 380).attr('fill','white');
const scatter = scatter_g.selectAll('circle').data(data).join('circle')
.attr('fill', d => color(d.label))
.attr('cx', d=>d.x)
.attr('cy', d=>d.y)
.attr('r', 5);
const control_g = svg.append('g').classed('scatterplot', true).attr('transform', 'translate(450,10)');
const labels = d3.range(10);
control_g.append('text').text('show/hide').attr('x',0).attr('y', 10).style('user-select', 'none');
const show_g = control_g.selectAll('g.show').data(labels).join('g').each(function(d) {
const g = d3.select(this);
let data = { label: d, show: true }
g.append('circle')
.classed('show', true)
.datum(data)
.attr('fill', d=>color(d.label))
.attr('stroke', d=>color(d.label))
.attr('stroke-width', 1)
.attr('cx', 20)
.attr('cy', d=>38 * (d.label + 1))
.attr('r', 5)
.on('click', function(d) {
d.show = !d.show;
d3.select(this).attr('fill', d=>d.show ? color(d.label) : 'white')
scatter.filter(dd=>dd.label === d.label).attr('display', !d.show ? 'none' : 'block');
});
g.append('text')
.text(d)
.attr('x', 40)
.attr('y', 38 * (d + 1))
.attr('dy', '0.3rem')
.style('user-select', 'none');
})
control_g.append('text').text('highlight').attr('x',100).attr('y', 10).style('user-select', 'none');
const highlight_g = control_g.selectAll('g.highlight').data(labels).join('g').each(function(d) {
const g = d3.select(this);
let data = { label: d, highlight: false }
g.append('circle')
.classed('highlight', true)
.datum(data)
.attr('fill', d=>color(d.label))
.attr('stroke', d=>color(d.label))
.attr('stroke-width', 1)
.attr('cx', 120)
.attr('cy', d=>38 * (d.label + 1))
.attr('r', 5)
.on('mouseover', function(d) {
d3.select(this).attr('r', 8);
scatter.filter(dd=>dd.label === d.label).raise().attr('r', 8);
})
.on('mouseout', function(d) {
d3.select(this).attr('r', d.highlight ? 8 : 5);
scatter.filter(dd=>dd.label === d.label).attr('r', d.highlight ? 8 : 5);
})
.on('click', function(d) {
d.highlight = !d.highlight;
});
g.append('text')
.text(d)
.attr('x', 140)
.attr('y', 38 * (d + 1))
.attr('dy', '0.3rem')
.style('user-select', 'none');
});
control_g.append('text').text('radio-highlight').attr('x',200).attr('y', 10).style('user-select', 'none');
const radio_controller = {
label: -1,
highlight: function(label) {
if (label === undefined) label = this.label;
scatter.attr('r', d=>d.label === label ? 8 : 5);
d3.selectAll('circle.radio-highlight').attr('r', d=>d.label === label ? 8 : 5);
},
};
const radio_highlight_g = control_g.selectAll('g.highlight').data(labels).join('g').each(function(d) {
const g = d3.select(this);
let data = { label: d }
g.append('circle')
.classed('radio-highlight', true)
.datum(data)
.attr('fill', d=>color(d.label))
.attr('stroke', d=>color(d.label))
.attr('stroke-width', 1)
.attr('cx', 220)
.attr('cy', d=>38 * (d.label + 1))
.attr('r', 5)
.on('mouseover', function(d) {
d3.select(this).attr('r', 8);
radio_controller.highlight(d.label);
})
.on('mouseout', function(d) {
d3.select(this).attr('r', d.highlight ? 8 : 5);
scatter.filter(dd=>dd.label === d.label).attr('r', d.highlight ? 8 : 5);
radio_controller.highlight();
})
.on('click', function(d) {
radio_controller.label = (radio_controller.label === d.label) ? -1 : d.label;
radio_controller.highlight();
});
g.append('text')
.text(d)
.attr('x', 240)
.attr('y', 38 * (d + 1))
.attr('dy', '0.3rem')
.style('user-select', 'none');
});
control_g.append('text').text('number').attr('x',350).attr('y', 10).style('user-select', 'none');
const bar_g = control_g.selectAll('g.highlight').data(labels).join('g').each(function(d) {
const g = d3.select(this);
let _data = { label: d, num: data.filter(dd=>dd.label===d).length, highlight: false }
g.append('rect')
.classed('bar', true)
.datum(_data)
.attr('fill', d=>color(d.label))
.attr('fill-opacity', 0.3)
.attr('stroke', d=>color(d.label))
.attr('stroke-width', 1)
.attr('x', 370)
.attr('y', d=>38 * (d.label + .75))
.attr('width', d=>5*d.num)
.attr('height', 38 * 0.5)
.on('mouseover', function(d) {
d3.select(this).attr('stroke-width', 3);
scatter.filter(dd=>dd.label === d.label).raise().attr('r', 8);
})
.on('mouseout', function(d) {
d3.select(this).attr('stroke-width', d.highlight ? 3 : 1);
scatter.filter(dd=>dd.label === d.label).attr('r', d.highlight ? 8 : 5);
})
.on('click', function(d) {
d.highlight = !d.highlight;
});
g.append('rect')
.classed('bar-dark', true)
.datum(_data)
.attr('fill', d=>color(d.label))
.attr('fill-opacity', 0.8)
.attr('stroke', d=>color(d.label))
.attr('stroke-width', 1)
.attr('x', 370)
.attr('y', d=>38 * (d.label + .75))
.attr('width', 0)
.attr('height', 38 * 0.5);
g.append('text')
.text(d)
.attr('x', 350)
.attr('y', 38 * (d + 1))
.attr('dy', '0.3rem')
.style('user-select', 'none');
});
const bar_highlight = function() {
const possible_item = scatter_g.selectAll('.possible');
const selected_item = scatter_g.selectAll('.selected');
d3.selectAll('rect.bar-dark')
.attr('width', d=>5*(possible_item.filter(dd => dd.label == d.label).size() + selected_item.filter(dd => dd.label == d.label).size()))
}
const lasso_start = function() {
console.log('start')
lasso.items()
.attr("r",5)
.classed("not_possible",true)
.classed("selected",false);
bar_highlight();
};
const lasso_draw = function() {
console.log('draw')
lasso.possibleItems()
.classed("not_possible",false)
.classed("possible",true)
.attr("r",8);
lasso.notPossibleItems()
.classed("not_possible",true)
.classed("possible",false)
.attr("r",5);
bar_highlight();
};
const lasso_end = function() {
console.log('end')
lasso.items()
.classed("not_possible",false)
.classed("possible",false);
lasso.selectedItems()
.classed("selected",true)
.attr("r",8);
lasso.notSelectedItems()
.attr("r",5);
bar_highlight();
};
const lasso = d3lasso.lasso()
.closePathDistance(305)
.closePathSelect(true)
.targetArea(scatter_g)
.items(scatter)
.on("start",lasso_start)
.on("draw",lasso_draw)
.on("end",lasso_end);
scatter_g.call(lasso);
return svg.node();
}