stacked = {
const width = 900;
const height = 500;
const marginTop = 80;
const marginRight = 30;
const marginBottom = 60;
const marginLeft = 90;
const swatchWidth = 20;
const frontColor = 'white',
bgColor = 'black',
mediumColor = '#aaa';
const stackedData = d3.stack()
.keys(Object.keys(data[0]).slice(1))
(data)
const pattern = textures.lines()
.size(6)
.strokeWidth(1)
.background("transparent")
.stroke(mediumColor);
const x = d3.scaleLinear()
.domain([0, 40])
.range([marginLeft, width - marginRight]);
const y = d3.scaleBand()
.domain(data.map(d => d.country))
.range([marginTop, height - marginBottom])
.paddingInner(0.6);
// - - - SVG elements - - - //
// Containers and defs
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.style("background-color", bgColor);
svg.call(pattern);
svg.select('defs')
.append("svg:marker")
.attr("id", "arrow")
.attr("viewBox", "0 0 6 12")
.attr("refX", 6)
.attr("refY", 6)
.attr("markerUnits", 'strokeWidth')
.attr("markerWidth", 6)
.attr("markerHeight", 12)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 L 6 6 L 0 12")
.attr("fill", "none")
.attr('stroke', frontColor)
.attr('stroke-width', 1)
svg.select('defs')
.append("svg:marker")
.attr("id", "circle")
.attr("viewBox", "0 0 12 12")
.attr("refX", 6)
.attr("refY", 6)
.attr("markerUnits", 'strokeWidth')
.attr("markerWidth", 12)
.attr("markerHeight", 12)
.attr("orient", "auto")
.append("circle")
.attr("cx", 6)
.attr("cy", 6)
.attr("r", 4)
.attr("fill", frontColor);
// Axis
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
const series = svg.selectAll("g.serie")
.data(stackedData)
.join("g")
.attr("class", "serie")
.attr('fill', d => d.key == 'real' ? frontColor : pattern.url());
// Rects
series.selectAll("rect")
.data(d => d)
.join("rect")
.attr('x', d => x(d[0]))
.attr('y', d => y(d.data.country))
.attr('height', d => y.bandwidth())
.attr('width', d => x(d[1]) - x(d[0]));
// Arrows
const misperception = series.filter(d => d.key == 'misperception');
misperception.selectAll("line")
.data(d => d.filter(v => v.data.country != 'España'))
.join("line")
.attr('x1', d => x(d[1]))
.attr('y1', d => y(d.data.country) + (y.bandwidth() / 2))
.attr('x2', d => x(d[0]))
.attr('y2', d => y(d.data.country) + (y.bandwidth() / 2))
.attr('marker-end', 'url(#arrow)')
.attr('marker-start', 'url(#circle)')
.attr('stroke', frontColor)
.attr('stroke-width', 2);
// Legend
const swatches = svg.append('g').selectAll('swatch')
.data(['Real', 'Perceived', 'Misperception'])
.join("g")
.attr("class", "swatch")
.attr('transform', (d, i) => `translate(${(i * 140) + marginLeft}, ${swatchWidth * 2})`);
swatches.filter(d => d != 'Perceived').selectAll('rect')
.data(d => [d])
.join('rect')
.attr('x', 0)
.attr('y', -swatchWidth)
.attr('width', swatchWidth)
.attr('height', swatchWidth)
.attr('fill', d => d == 'Real' ? frontColor : pattern.url())
swatches.filter(d => d == 'Perceived').selectAll('circle')
.data(d => [d])
.join('circle')
.attr('cx', 0)
.attr('cy', -swatchWidth / 2)
.attr('r', swatchWidth / 2)
.attr('height', swatchWidth)
.attr('fill', frontColor)
swatches.selectAll('text')
.data(d => [d])
.join('text')
.attr('x', swatchWidth + 4)
.attr('y', -4)
.text(d => d)
.attr("fill", frontColor);
return svg.node();
}