UNPKG

@labvis-ufpa/vistechlib

Version:

Information Visualization Technique Library

311 lines (257 loc) 11.4 kB
let d3 = require("d3"); let _ = require("underscore"); let Visualization = require("./Visualization.js"); let utils = require("./Utils.js"); class ScatterplotMatrix extends Visualization{ constructor(parentElement, settings){ super(parentElement, settings); this.name = "ScatterplotMatrix"; } _putDefaultSettings(){ this.settings.innerPadding = 8; this.settings.paddingRight = 20; } resize(){ let pl = this.settings.paddingLeft; let pr = this.settings.paddingRight; let pt = this.settings.paddingTop; let pb = this.settings.paddingBottom; let ip = this.settings.innerPadding; let svgBounds = this.svg.node().getBoundingClientRect(); this.cellWidth = (svgBounds.width-pl-pr-ip*(this.keys.length-1))/this.keys.length; this.cellHeight = (svgBounds.height-pt-pb-ip*(this.keys.length-1))/this.keys.length; for(let k of this.keys){ // if(this.domainType[k] === "Categorical"){ // this.x[k].rangePoints([0, this.cellWidth], 0); // this.y[k].rangePoints([0, this.cellHeight], 0); // }else{ this.x[k].range([0, this.cellWidth]); this.y[k].range([this.cellHeight, 0]); // } } // console.log("redraw"); this.redraw(); return this; } data(d){ let pt = this.settings.paddingTop; let pb = this.settings.paddingBottom; let pl = this.settings.paddingLeft; let pr = this.settings.paddingRight; let ip = this.settings.innerPadding; super.data(d); let svgBounds = this.svg.node().getBoundingClientRect(); this.cellWidth = (svgBounds.width-pl-pr-ip*(this.keys.length-1))/this.keys.length; this.cellHeight = (svgBounds.height-pt-pb-ip*(this.keys.length-1))/this.keys.length; this.x = {}; this.y = {}; for(let k of this.keys){ if(this.domainType[k] === "Categorical"){ this.x[k] = d3.scalePoint() .domain(this.domain[k]) .range([0, this.cellWidth]); this.y[k] = d3.scalePoint() .domain(this.domain[k]) .range([0, this.cellHeight]); }else{ this.x[k] = d3.scaleLinear() .domain(this.domain[k]) .range([0, this.cellWidth]); this.y[k] = d3.scaleLinear() .domain(this.domain[k]) .range([this.cellHeight, 0]); } } return this; } redraw(){ //Atualiza os Eixos let y_axes = this.y; let crossed = ScatterplotMatrix.cross(this.keys, this.keys); let scatterplot = this; function redrawDataPoints(k) { let cell = d3.select(this); let dataEnter = cell.selectAll("circle.data") .data(scatterplot.d).enter() .append("circle") .attr("class", "data") .attr("data-index", function(d,i){ return i; }) .attr("data-col", k.x) .attr("data-row", k.y) .attr("cx", function(d) { return scatterplot.x[k.x](d[k.x]); }) .attr("cy", function(d) { return scatterplot.y[k.y](d[k.y]); }) .attr("r", 2) .style("fill", scatterplot.settings.color) .style("fill-opacity", ".7"); scatterplot._bindDataMouseEvents(dataEnter); cell.selectAll("circle.data") .data(scatterplot.d) .attr("cx", function(d) { return scatterplot.x[k.x](d[k.x]); }) .attr("cy", function(d) { return scatterplot.y[k.y](d[k.y]); }) .style("fill", scatterplot.settings.color); cell.selectAll("circle.data") .data(scatterplot.d).exit().remove(); } let scatterGroups = this.foreground.selectAll("g.cellGroup").data(crossed); scatterGroups.exit().remove(); scatterGroups .attr("transform", (d) => { return "translate(" + d.i * (this.cellWidth+this.settings.innerPadding) + "," + d.j * (this.cellHeight+this.settings.innerPadding) + ")"; }) .each(redrawDataPoints); let scatterGroupEnter = scatterGroups.enter() .append("g") .attr("class", "cellGroup") .attr("transform", (d) => { return "translate(" + d.i * (this.cellWidth+this.settings.innerPadding) + "," + d.j * (this.cellHeight+this.settings.innerPadding) + ")"; }) .each(redrawDataPoints); scatterGroupEnter.append("rect") .attr("class", "frame") .attr("x", 0) .attr("y", 0) .attr("width", scatterplot.cellWidth) .attr("height", scatterplot.cellHeight) .style("fill", "none") .style("stroke", "#aaa"); scatterGroups .selectAll("rect.frame") .attr("width", scatterplot.cellWidth) .attr("height", scatterplot.cellHeight); scatterGroupEnter .filter(function(d) { return d.i === d.j; }) .append("text") .attr("class", "axisLabel") .style("fill", "black") .attr("x", scatterplot.settings.innerPadding) .attr("y", scatterplot.settings.innerPadding) .attr("dy", ".71em") .text(function(d) { return d.x; }); scatterGroups .selectAll("text.axisLabel") .text(function(d) { return d.x; }); // this.foreground.selectAll("g.cellGroup").selectAll("text.axisLabel").remove(); // this.foreground.selectAll("g.cellGroup") // .filter(function(d) { return d.i === d.j; }) // .append("text") // .attr("class", "axisLabel") // .attr("x", scatterplot.settings.innerPadding) // .attr("y", scatterplot.settings.innerPadding) // .attr("dy", ".71em") // .text(function(d) { return d.x; }); this.foreground.selectAll(".x.axis").remove(); this.foreground.selectAll(".x.axis") .data(this.keys) .enter().append("g") .attr("class", "x axis") .attr("transform", (d, i) => { return "translate(" + i * (this.cellWidth+this.settings.innerPadding) + "," + (this.svg.node().getBoundingClientRect().height -this.settings.paddingBottom-this.settings.paddingTop) +")"; }) .each(function(d) { d3.select(this).call(d3.axisBottom(scatterplot.x[d]).ticks(6)); }); this.foreground.selectAll(".y.axis").remove(); this.foreground.selectAll(".y.axis") .data(this.keys) .enter().append("g") .attr("class", "y axis") .attr("transform", (d, i) => { return "translate(0," + i * (this.cellHeight+this.settings.innerPadding) + ")"; }) .each(function(d) { d3.select(this).call(d3.axisLeft(scatterplot.y[d]).ticks(6)); }); this.event.apply("draw"); return this; } highlight(...args){ let highlighted; if(typeof args[1] === "number" && args[1] >= 0 && args[1] < this.d.length){ // this.foreground.select // d3.select(args[0]) let strObj = {}, isFirst = {}; for(let k of this.keys){ strObj[k] = "M "; isFirst[k] = true; } highlighted = this.foreground .selectAll('circle.data[data-index="'+args[1]+'"]') .style("stroke", this.settings.highlightColor) .each(function(){ let circle = d3.select(this); let t = utils.parseTranslate(this.parentElement); if(isFirst[circle.attr("data-row")]){ strObj[circle.attr("data-row")] += (parseFloat(circle.attr("cx")) + t.x) +" "+(parseFloat(circle.attr("cy")) + t.y); isFirst[circle.attr("data-row")] = false; }else{ strObj[circle.attr("data-row")] += " Q "+ + t.x+ " " + t.y + " , " + (parseFloat(circle.attr("cx")) + t.x) + " " +(parseFloat(circle.attr("cy")) + t.y); } }); this.background .selectAll("path.lineHighlight") .data(_.values(strObj)).enter() .append("path") .attr("class", "lineHighlight") .attr("d", function(d) { return d; }) .style("fill", "none") .style("stroke", this.settings.highlightColor); } if(highlighted) super.highlight(highlighted.nodes(), args[0], args[1], args[2]); } removeHighlight(...args){ if(typeof args[1] === "number" && args[1] >= 0 && args[1] < this.d.length){ let elem = this.foreground.selectAll('circle.data[data-index="'+args[1]+'"]').style("stroke", "none"); this.background.selectAll(".lineHighlight").remove(); super.removeHighlight(elem.node(), elem.datum(), args[1]); } } getHighlightElement(i){ let group = document.createElementNS("http://www.w3.org/2000/svg", "g"); d3.select(group).attr("class", "groupHighlight"); let strObj = {}, isFirst = {}; for(let k of this.keys){ strObj[k] = "M "; isFirst[k] = true; } this.foreground.selectAll('circle.data[data-index="'+i+'"]') .each(function(){ let circle = d3.select(this); let t = utils.parseTranslate(this.parentElement); if(isFirst[circle.attr("data-row")]){ strObj[circle.attr("data-row")] += (parseFloat(circle.attr("cx")) + t.x) +" "+(parseFloat(circle.attr("cy")) + t.y); isFirst[circle.attr("data-row")] = false; }else{ strObj[circle.attr("data-row")] += " Q "+ + t.x+ " " + t.y + " , " + (parseFloat(circle.attr("cx")) + t.x) + " " +(parseFloat(circle.attr("cy")) + t.y); } }); for(let d of _.values(strObj)){ let path = document.createElementNS("http://www.w3.org/2000/svg", "path"); d3.select(path) .attr("class", "lineHighlight") .style("fill", "none") .style("stroke", this.settings.highlightColor) .attr("d", d); group.appendChild(path); } return group; } static cross(a, b) { let c = [], n = a.length, m = b.length, i, j; for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j}); return c; } } module.exports = ScatterplotMatrix;