How can I make overlapping parts in a d3.js radar chart transparent.
The radar chart blobs below are created with d3.js. The space where red and green intersect should be made transparent (This will serve for a before <-> after comparison). The snippet below the chart contains the code for creating the radar chart. I didn't include the 5 axes for simplicity:
/* Original radar chart design created by Nadieh Bremer - VisualCinnamon.com */
////////////////////////// Data //////////////////////////////
var data = [
[//Before - red
{axis:"First",value:0.49},
{axis:"Banana",value:0.79},
{axis:"Scratch",value:0.70},
{axis:"Wheelie",value:0.09},
{axis:"Pantalon",value:0.37},
],[//After - green
{axis:"First",value:0.64},
{axis:"Banana",value:0.44},
{axis:"Scratch",value:0.37},
{axis:"Wheelie",value:0.84},
{axis:"Pantalon",value:0.81},
]
];
//////////////////////// Setup ////////////////////////////////
var margin = {top: 50, right: 50, bottom: 50, left: 50},
width = 300,
height = 300;
var color = d3.scale.ordinal().range(["#CC333F","#53e87d"]);
var radarChartOptions = {
w: width, //Width of the circle
h: height, //Height of the circle
margin: margin, //The margins of the SVG
opacityArea: 0.7, //The opacity of the area of the blob
color: color //Color function
};
//////////////////////// RadarChart ///////////////////////////
RadarChart("#radarChart1", data, radarChartOptions);
/////////////////////////////////////////////////////////
/////////////// The Radar Chart Function ////////////////
/////////////// Written by Nadieh Bremer ////////////////
////////////////// VisualCinnamon.com ///////////////////
/////////// Inspired by the code of alangrafu ///////////
/////////////////////////////////////////////////////////
function RadarChart(id, data, options) {
/////////////////////////////////////////////////////////
/////////////// Prep ////////////////
/////////////////////////////////////////////////////////
var cfg = radarChartOptions;
var allAxis = (data[0].map(function(i, j){return i.axis})), //Names of each axis
total = allAxis.length, //The number of different axes
radius = Math.min(cfg.w/2, cfg.h/2), //Radius of the outermost circle
Format = d3.format('%'), //Percentage formatting
angleSlice = Math.PI * 2 / total; //The width in radians of each "slice"
var rScale = d3.scale.linear() //Scale for the radius
.range([0, radius]);
//////////// Create the container SVG and g /////////////
var svg = d3.select(id).append("svg") //Initiate the radar chart SVG
.attr("width", cfg.w + cfg.margin.left + cfg.margin.right)
.attr("height", cfg.h + cfg.margin.top + cfg.margin.bottom)
.attr("class", "radar"+id);
var g = svg.append("g") //Append a g element
.attr("transform", "translate(" + (cfg.w/2 + cfg.margin.left) + "," + (cfg.h/2 + cfg.margin.top) + ")");
/////////////////////////////////////////////////////////
///////////// Draw the radar chart blobs ////////////////
/////////////////////////////////////////////////////////
//The radial line function
var radarLine = d3.svg.line.radial()
.interpolate("cardinal-closed")
.radius(function(d) { return rScale(d.value); })
.angle(function(d,i) { return i*angleSlice; });
//Create a wrapper for the blobs
var blobWrapper = g.selectAll(".radarWrapper")
.data(data)
.enter().append("g")
.attr("class", "radarWrapper");
//Append the backgrounds
blobWrapper
.append("path")
.attr("class", "radarArea")
.attr("d", function(d,i) { return radarLine(d); })
.style("fill", function(d,i) { return cfg.color(i);})
.style("fill-opacity", cfg.opacityArea);
}//RadarChart function
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!-- Radar Chart -->
<div class="radar-chart" id="radarChart1"></div>
I found that in HTML5-Canvas overlapping elements can be made transparent (1). It can also be used to bind d3 nodes to it (2) and they could made transparent this way. However, this seems very complicated for more complex objects like the above radar-chart blobs. Is there an easy solution to do this in d3? (There seems to be one in chart.js (3))
Addendum - What I already found:
- Overlapping (non-d3) elements can be made transparent using HTML5-Canvas by setting the
globalCompositeOperationmode to'xor':
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'xor';
// WITHOUT overlap:
ctx.fillStyle = 'blue';
ctx.fillRect(10, 10, 100, 100);
ctx.fillStyle = 'red';
ctx.fillRect(110, 50, 100, 100);
// WITH (transparent) overlap:
ctx.fillStyle = 'blue';
ctx.fillRect(250, 10, 100, 100);
ctx.fillStyle = 'red';
ctx.fillRect(300, 50, 100, 100);
<!-- Original from https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation -->
<style>
body {
background-image: url("http://www.scri8e.com/stars/PNG_Clouds/zc06.png?filename=./zc06.png");
}
</style>
<canvas id="canvas" width="400" height="200" ></canvas>
d3.js nodes can also be visualized by HTML5-Canvas by using getContext("2d"). Overlaps can be implemented the same way as above (1). However, to my understanding this requires to recreate each element in Javascript and then bind the d3 data on it. For example for circles, arc elements have to be recreated in the HTML5-Canvas context as in this example by Mike Bostock:
context = canvas.getContext("2d"); ... context.arc(element.getAttribute("x"), element.getAttribute("y"), element.getAttribute("radius"), 0, 2 * Math.PI);Here is a possible implementation in chartjs (see picture below)


