react-venn-diagram
Version:
A Venn diagram React component
106 lines (105 loc) • 4.46 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { useEffect, useRef } from 'react';
import * as d3 from 'd3';
var VennDiagram = function (_a) {
var _b = _a.data, a = _b.a, b = _b.b, intersection = _b.intersection, width = _a.width, height = _a.height, _c = _a.labels, labels = _c === void 0 ? {} : _c, _d = _a.colors, colors = _d === void 0 ? {} : _d;
var svgRef = useRef(null);
useEffect(function () {
if (!svgRef.current)
return;
var svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
var scale = d3.scaleSqrt()
.domain([0, Math.max(a, b)])
.range([0, width / 5]);
var radiusA = scale(a);
var radiusB = scale(b);
var positions = {
A: { cx: width / 2 - radiusB / 2, cy: height / 2 },
B: { cx: width / 2 + radiusA / 2, cy: height / 2 },
};
var handleMouseOver = function () {
d3.select(this)
.transition()
.duration(300)
.style('fill-opacity', 0.7);
};
var handleMouseOut = function () {
d3.select(this)
.transition()
.duration(300)
.style('fill-opacity', 0.5);
};
var drawCircleAndText = function (key, value, label, color, fontColor) {
var pos = positions[key];
var radius = key === 'A' ? radiusA : radiusB;
var circle = svg.append('circle')
.attr('cx', pos.cx)
.attr('cy', pos.cy)
.attr('r', 0)
.style('fill', color)
.style('fill-opacity', 0.5)
.transition()
.duration(800)
.attr('r', radius)
.on('end', function () {
d3.select(this)
.on('mouseover', handleMouseOver)
.on('mouseout', handleMouseOut)
.on('touchstart', handleMouseOver)
.on('touchend', handleMouseOut);
});
var textX = key === 'A' ? pos.cx - radius : pos.cx + radius;
var textAnchor = key === 'A' ? 'start' : 'end';
var textElement = svg.append('text')
.attr('x', textX)
.attr('y', pos.cy)
.style('fill', fontColor)
.style('font-size', '14px')
.style('font-family', 'Arial, sans-serif')
.attr('text-anchor', textAnchor)
.style('opacity', 0);
textElement.transition()
.duration(800)
.style('opacity', 1);
textElement.append("tspan")
.attr('x', textX)
.attr('dy', '0em')
.style('font-weight', 'bold')
.text("".concat(value));
textElement.append("tspan")
.attr('x', textX)
.attr('dy', '1.2em')
.text(label);
};
drawCircleAndText('A', a, labels.labelA || 'Group A', colors.colorA || '#9467bd', colors.fontColorA || 'white');
drawCircleAndText('B', b, labels.labelB || 'Group B', colors.colorB || '#2ca02c', colors.fontColorB || 'white');
var intersectionCenterX = (positions.A.cx + positions.B.cx) / 2;
var intersectionTextElement = svg.append('text')
.attr('x', intersectionCenterX)
.attr('y', height / 2)
.style('fill', colors.fontColorIntersection || 'white')
.style('font-size', '12px')
.style('font-family', 'Arial, sans-serif')
.attr('text-anchor', 'middle')
.style('opacity', 0);
intersectionTextElement.transition()
.duration(800)
.style('opacity', 1)
.tween("text", function () {
var self = this;
return function () {
d3.select(self).text("".concat(intersection));
};
})
.on("end", function () {
d3.select(this).append("tspan")
.attr('x', intersectionCenterX)
.attr('dy', '1.2em')
.style('font-weight', 'normal')
.text(labels.labelIntersection || 'Intersection');
});
}, [a, b, intersection, width, height, labels, colors]);
return _jsx("svg", { ref: svgRef, width: width, height: height });
};
export default VennDiagram;