/** * @upsetjs/react * https://github.com/upsetjs/upsetjs * * Copyright (c) 2021 Samuel Gratzl */ import { isSet, isSetLike } from '@upsetjs/model'; import React, { Ref, useMemo } from 'react'; import { fillVennDiagramDefaults } from '../fillDefaults'; import type { VennDiagramProps } from '../interfaces'; import { clsx, generateSelectionName, generateSelectionOverlap } from '../utils'; import SVGWrapper from './components/SVGWrapper'; import VennArcSliceSelection from './components/VennArcSliceSelection'; import deriveVennDataDependent from './derive/deriveVennDataDependent'; import { useCreateCommon, useExportChart } from './hooks'; import UpSetTitle from '../components/UpSetTitle'; import { isEllipse } from './layout/interfaces'; export const VennDiagram = /*!#__PURE__*/ React.forwardRef(function VennDiagram( props: VennDiagramProps, ref: Ref ) { const p = fillVennDiagramDefaults(props); const { selection = null, queries = [], fontSizes } = p; const v = useCreateCommon(p); const { size, style, rulesHelper } = v; const dataInfo = useMemo( () => deriveVennDataDependent( p.sets, p.combinations, size, p.layout, p.valueFormat, p.toKey, p.toElemKey, p.id, p.setLabelOffsets ), [p.sets, p.combinations, size, p.valueFormat, p.toKey, p.toElemKey, p.id, p.layout, p.setLabelOffsets] ); const selectionKey = selection != null && isSetLike(selection) ? p.toKey(selection) : null; const selectionOverlap = selection == null ? null : generateSelectionOverlap(selection, dataInfo.overlapGuesser, dataInfo.toElemKey); const selectionName = generateSelectionName(selection); const rules = ` ${rulesHelper.root} ${rulesHelper.text} .valueTextStyle-${style.id} { fill: ${p.valueTextColor}; ${rulesHelper.p(fontSizes.valueLabel)} text-anchor: middle; dominant-baseline: central; } .setTextStyle-${style.id} { fill: ${p.textColor}; ${rulesHelper.p(fontSizes.setLabel)} text-anchor: middle; } .topText-${style.id} { dominant-baseline: hanging; } .stroke-circle-${style.id} { fill: none; stroke: ${p.strokeColor}; } .arc-${style.id} { fill-rule: evenodd; } .arcP-${style.id} { fill: transparent; fill-opacity: ${p.opacity}; } ${rulesHelper.fill} ${rulesHelper.export} ${rulesHelper.hasSFill ? `.root-${style.id}[data-selection] .arcP-${style.id} { ${rulesHelper.hasSFill} }` : ''} ${queries .map( (q, i) => `.fillQ${i}-${dataInfo.id} { fill: ${q.color}; }` ) .join('\n')} `; const exportChart = useExportChart(dataInfo, p, 'venn'); const maxWidth = dataInfo.sets.d.reduce( (acc, d) => Math.min(acc, d.l.cx - (isEllipse(d.l) ? d.l.rx : d.l.r)), size.area.w ); return ( {dataInfo.sets.d.map((d, i) => ( {style.tooltips && ( {dataInfo.sets.v[i].name}: {dataInfo.format(dataInfo.sets.v[i].cardinality)} )} {dataInfo.sets.v[i].name} ))} {dataInfo.cs.d.map((l, i) => ( ))} {dataInfo.sets.d.map((l) => isEllipse(l.l) ? ( ) : ( ) )} ); }); /** * VennDiagram main pure functional stateless React component, the generic argument T refers to the type of the elements * * with React.forwardRef support to specify a reference to the SVG element */ export default VennDiagram as (p: VennDiagramProps & React.RefAttributes) => React.ReactElement;