@upsetjs/venn.js
Advanced tools
Comparing version 1.1.0 to 1.2.0
import { nelderMead, bisect, norm2, zeros, conjugateGradient, scale, zerosM } from 'fmin'; | ||
import { select } from 'd3-selection'; | ||
import 'd3-transition'; | ||
@@ -1164,3 +1162,3 @@ const SMALL = 1e-10; | ||
svg.selectAll('.venn-area path').each(function (d) { | ||
var path = select(this).attr('d'); | ||
const path = this.getAttribute('d'); | ||
if (d.sets.length == 1 && path) { | ||
@@ -1237,6 +1235,13 @@ hasPrevious = true; | ||
function asTransition(s) { | ||
if (typeof s.transition === 'function') { | ||
return s.transition('venn').duration(duration); | ||
} | ||
return s; | ||
} | ||
// update existing, using pathTween if necessary | ||
let update = selection; | ||
if (hasPrevious) { | ||
update = selection.transition('venn').duration(duration); | ||
update = asTransition(selection); | ||
update.selectAll('path').attrTween('d', pathTween); | ||
@@ -1269,3 +1274,3 @@ } else { | ||
// remove old | ||
const exit = nodes.exit().transition('venn').duration(duration).remove(); | ||
const exit = asTransition(nodes.exit()).remove(); | ||
exit.selectAll('path').attrTween('d', pathTween); | ||
@@ -1389,5 +1394,4 @@ | ||
function wrapText(circles, labeller) { | ||
return function () { | ||
const text = select(this); | ||
const data = text.datum(); | ||
return function (data) { | ||
const text = this; | ||
const width = circles[data.sets[0]].radius || 50; | ||
@@ -1401,7 +1405,17 @@ const label = labeller(data) || ''; | ||
let word = words.pop(); | ||
const line = [word]; | ||
let line = [word]; | ||
let lineNumber = 0; | ||
const lineHeight = 1.1; // ems | ||
let tspan = text.text(null).append('tspan').text(word); | ||
text.textContent = null; // clear | ||
const tspans = []; | ||
function append(word) { | ||
const tspan = text.ownerDocument.createElementNS(text.namespaceURI, 'tspan'); | ||
tspan.textContent = word; | ||
tspans.push(tspan); | ||
text.append(tspan); | ||
return tspan; | ||
} | ||
let tspan = append(word); | ||
while (true) { | ||
@@ -1414,8 +1428,8 @@ word = words.pop(); | ||
const joined = line.join(' '); | ||
tspan.text(joined); | ||
if (joined.length > minChars && tspan.node().getComputedTextLength() > width) { | ||
tspan.textContent = joined; | ||
if (joined.length > minChars && tspan.getComputedTextLength() > width) { | ||
line.pop(); | ||
tspan.text(line.join(' ')); | ||
tspan.textContent = line.join(' '); | ||
line = [word]; | ||
tspan = text.append('tspan').text(word); | ||
tspan = append(word); | ||
lineNumber++; | ||
@@ -1426,10 +1440,9 @@ } | ||
const initial = 0.35 - (lineNumber * lineHeight) / 2; | ||
const x = text.attr('x'); | ||
const y = text.attr('y'); | ||
text | ||
.selectAll('tspan') | ||
.attr('x', x) | ||
.attr('y', y) | ||
.attr('dy', (_, i) => `${initial + i * lineHeight}em`); | ||
const x = text.getAttribute('x'); | ||
const y = text.getAttribute('y'); | ||
tspans.forEach((t, i) => { | ||
t.setAttribute('x', x); | ||
t.setAttribute('y', y); | ||
t.setAttribute('dy', `${initial + i * lineHeight}em`); | ||
}); | ||
}; | ||
@@ -1716,6 +1729,6 @@ } | ||
function computeVennLayout(data, options = {}) { | ||
function layout(data, options = {}) { | ||
const { | ||
lossFunction = lossFunction, | ||
layoutFunction = layoutFunction, | ||
lossFunction: loss = lossFunction, | ||
layoutFunction: layout = venn, | ||
normalize = true, | ||
@@ -1731,3 +1744,3 @@ orientation = Math.PI / 2, | ||
let solution = layoutFunction(data, { lossFunction }); | ||
let solution = layout(data, { lossFunction: loss }); | ||
@@ -1749,3 +1762,2 @@ if (normalize) { | ||
radius: circles[set].radius, | ||
text: textCentres[set], | ||
}, | ||
@@ -1759,3 +1771,4 @@ ]) | ||
return { | ||
data, | ||
data: area, | ||
text: textCentres[area.sets], | ||
circles, | ||
@@ -1768,2 +1781,2 @@ arcs, | ||
export { VennDiagram, bestInitialLayout, circleArea, circleCircleIntersection, circleFromPath, circleOverlap, circlePath, computeTextCentre, computeTextCentres, computeVennLayout, disjointCluster, distance, distanceFromIntersectArea, greedyLayout, intersectionArea, intersectionAreaPath, lossFunction, normalizeSolution, scaleSolution, sortAreas, venn, wrapText }; | ||
export { VennDiagram, bestInitialLayout, circleArea, circleCircleIntersection, circleFromPath, circleOverlap, circlePath, computeTextCentre, computeTextCentres, disjointCluster, distance, distanceFromIntersectArea, greedyLayout, intersectionArea, intersectionAreaPath, layout, lossFunction, normalizeSolution, scaleSolution, sortAreas, venn, wrapText }; |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("d3-selection"),require("d3-transition")):"function"==typeof define&&define.amd?define(["exports","d3-selection","d3-transition"],e):e((t=t||self).venn={},t.d3)}(this,function(t,e){"use strict";const n=1e-10;function r(t,e){const r=function(t){const e=[];for(let n=0;n<t.length;++n)for(let r=n+1;r<t.length;++r){const s=a(t[n],t[r]);for(const t of s)t.parentIndex=[n,r],e.push(t)}return e}(t),o=r.filter(e=>(function(t,e){return e.every(e=>i(t,e)<e.radius+n)})(e,t));let c=0,u=0;const f=[];if(o.length>1){const e=l(o);for(let t=0;t<o.length;++t){const n=o[t];n.angle=Math.atan2(n.x-e.x,n.y-e.y)}o.sort((t,e)=>e.angle-t.angle);let n=o[o.length-1];for(let e=0;e<o.length;++e){const r=o[e];u+=(n.x+r.x)*(r.y-n.y);const a={x:(r.x+n.x)/2,y:(r.y+n.y)/2};let l=null;for(let e=0;e<r.parentIndex.length;++e)if(n.parentIndex.includes(r.parentIndex[e])){const s=t[r.parentIndex[e]],o=Math.atan2(r.x-s.x,r.y-s.y),c=Math.atan2(n.x-s.x,n.y-s.y);let u=c-o;u<0&&(u+=2*Math.PI);const f=c-u/2;let x=i(a,{x:s.x+s.radius*Math.sin(f),y:s.y+s.radius*Math.cos(f)});x>2*s.radius&&(x=2*s.radius),(null==l||l.width>x)&&(l={circle:s,width:x,p1:r,p2:n})}null!=l&&(f.push(l),c+=s(l.circle.radius,l.width),n=r)}}else{let e=t[0];for(let n=1;n<t.length;++n)t[n].radius<e.radius&&(e=t[n]);let r=!1;for(let n=0;n<t.length;++n)if(i(t[n],e)>Math.abs(e.radius-t[n].radius)){r=!0;break}r?c=u=0:(c=e.radius*e.radius*Math.PI,f.push({circle:e,p1:{x:e.x,y:e.y+e.radius},p2:{x:e.x-n,y:e.y+e.radius},width:2*e.radius}))}return u/=2,e&&(e.area=c+u,e.arcArea=c,e.polygonArea=u,e.arcs=f,e.innerPoints=o,e.intersectionPoints=r),c+u}function s(t,e){return t*t*Math.acos(1-e/t)-(t-e)*Math.sqrt(e*(2*t-e))}function i(t,e){return Math.sqrt((t.x-e.x)*(t.x-e.x)+(t.y-e.y)*(t.y-e.y))}function o(t,e,n){if(n>=t+e)return 0;if(n<=Math.abs(t-e))return Math.PI*Math.min(t,e)*Math.min(t,e);const r=e-(n*n-t*t+e*e)/(2*n);return s(t,t-(n*n-e*e+t*t)/(2*n))+s(e,r)}function a(t,e){const n=i(t,e),r=t.radius,s=e.radius;if(n>=r+s||n<=Math.abs(r-s))return[];const o=(r*r-s*s+n*n)/(2*n),a=Math.sqrt(r*r-o*o),l=t.x+o*(e.x-t.x)/n,c=t.y+o*(e.y-t.y)/n,u=-(e.y-t.y)*(a/n),f=-(e.x-t.x)*(a/n);return[{x:l+u,y:c-f},{x:l-u,y:c+f}]}function l(t){const e={x:0,y:0};for(const n of t)e.x+=n.x,e.y+=n.y;return e.x/=t.length,e.y/=t.length,e}"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var c,u,f=(function(t,e){!function(t){function e(t){for(var e=new Array(t),n=0;n<t;++n)e[n]=0;return e}function n(t,e){for(var n=0,r=0;r<t.length;++r)n+=t[r]*e[r];return n}function r(t){return Math.sqrt(n(t,t))}function s(t,e,n){for(var r=0;r<e.length;++r)t[r]=e[r]*n}function i(t,e,n,r,s){for(var i=0;i<t.length;++i)t[i]=e*n[i]+r*s[i]}function o(t,e,r,s,o,a,l){var c=r.fx,u=n(r.fxprime,e),f=c,x=c,h=u,d=0;function p(x,d,p){for(var g=0;g<16;++g)if(o=(x+d)/2,i(s.x,1,r.x,o,e),f=s.fx=t(s.x,s.fxprime),h=n(s.fxprime,e),f>c+a*o*u||f>=p)d=o;else{if(Math.abs(h)<=-l*u)return o;h*(d-x)>=0&&(d=x),x=o,p=f}return 0}o=o||1,a=a||1e-6,l=l||.1;for(var g=0;g<10;++g){if(i(s.x,1,r.x,o,e),f=s.fx=t(s.x,s.fxprime),h=n(s.fxprime,e),f>c+a*o*u||g&&f>=x)return p(d,o,x);if(Math.abs(h)<=-l*u)return o;if(h>=0)return p(o,d,f);x=f,d=o,o*=2}return o}t.bisect=function(t,e,n,r){var s=(r=r||{}).maxIterations||100,i=r.tolerance||1e-10,o=t(e),a=t(n),l=n-e;if(o*a>0)throw"Initial bisect points must have opposite signs";if(0===o)return e;if(0===a)return n;for(var c=0;c<s;++c){var u=e+(l/=2),f=t(u);if(f*o>=0&&(e=u),Math.abs(l)<i||0===f)return u}return e+l},t.nelderMead=function(t,e,n){var r,s=(n=n||{}).maxIterations||200*e.length,o=n.nonZeroDelta||1.05,a=n.zeroDelta||.001,l=n.minErrorDelta||1e-6,c=n.minErrorDelta||1e-5,u=void 0!==n.rho?n.rho:1,f=void 0!==n.chi?n.chi:2,x=void 0!==n.psi?n.psi:-.5,h=void 0!==n.sigma?n.sigma:.5,d=e.length,p=new Array(d+1);p[0]=e,p[0].fx=t(e),p[0].id=0;for(var g=0;g<d;++g){var y=e.slice();y[g]=y[g]?y[g]*o:a,p[g+1]=y,p[g+1].fx=t(y),p[g+1].id=g+1}function m(t){for(var e=0;e<t.length;e++)p[d][e]=t[e];p[d].fx=t.fx}for(var M=function(t,e){return t.fx-e.fx},v=e.slice(),b=e.slice(),z=e.slice(),I=e.slice(),w=0;w<s;++w){if(p.sort(M),n.history){var R=p.map(function(t){var e=t.slice();return e.fx=t.fx,e.id=t.id,e});R.sort(function(t,e){return t.id-e.id}),n.history.push({x:p[0].slice(),fx:p[0].fx,simplex:R})}for(r=0,g=0;g<d;++g)r=Math.max(r,Math.abs(p[0][g]-p[1][g]));if(Math.abs(p[0].fx-p[d].fx)<l&&r<c)break;for(g=0;g<d;++g){v[g]=0;for(var F=0;F<d;++F)v[g]+=p[F][g];v[g]/=d}var A=p[d];if(i(b,1+u,v,-u,A),b.fx=t(b),b.fx<p[0].fx)i(I,1+f,v,-f,A),I.fx=t(I),I.fx<b.fx?m(I):m(b);else if(b.fx>=p[d-1].fx){var P=!1;if(b.fx>A.fx?(i(z,1+x,v,-x,A),z.fx=t(z),z.fx<A.fx?m(z):P=!0):(i(z,1-x*u,v,x*u,A),z.fx=t(z),z.fx<b.fx?m(z):P=!0),P){if(h>=1)break;for(g=1;g<p.length;++g)i(p[g],1-h,p[0],h,p[g]),p[g].fx=t(p[g])}}else m(b)}return p.sort(M),{fx:p[0].fx,x:p[0]}},t.conjugateGradient=function(t,e,a){var l,c,u,f={x:e.slice(),fx:0,fxprime:e.slice()},x={x:e.slice(),fx:0,fxprime:e.slice()},h=e.slice(),d=1;u=(a=a||{}).maxIterations||20*e.length,f.fx=t(f.x,f.fxprime),s(l=f.fxprime.slice(),f.fxprime,-1);for(var p=0;p<u;++p){if(d=o(t,l,f,x,d),a.history&&a.history.push({x:f.x.slice(),fx:f.fx,fxprime:f.fxprime.slice(),alpha:d}),d){i(h,1,x.fxprime,-1,f.fxprime);var g=n(f.fxprime,f.fxprime),y=Math.max(0,n(h,x.fxprime)/g);i(l,y,l,-1,x.fxprime),c=f,f=x,x=c}else s(l,f.fxprime,-1);if(r(f.fxprime)<=1e-5)break}return a.history&&a.history.push({x:f.x.slice(),fx:f.fx,fxprime:f.fxprime.slice(),alpha:d}),f},t.gradientDescent=function(t,e,n){for(var s=(n=n||{}).maxIterations||100*e.length,o=n.learnRate||.001,a={x:e.slice(),fx:0,fxprime:e.slice()},l=0;l<s&&(a.fx=t(a.x,a.fxprime),n.history&&n.history.push({x:a.x.slice(),fx:a.fx,fxprime:a.fxprime.slice()}),i(a.x,1,a.x,-o,a.fxprime),!(r(a.fxprime)<=1e-5));++l);return a},t.gradientDescentLineSearch=function(t,e,n){n=n||{};var i,a={x:e.slice(),fx:0,fxprime:e.slice()},l={x:e.slice(),fx:0,fxprime:e.slice()},c=n.maxIterations||100*e.length,u=n.learnRate||1,f=e.slice(),x=n.c1||.001,h=n.c2||.1,d=[];if(n.history){var p=t;t=function(t,e){return d.push(t.slice()),p(t,e)}}a.fx=t(a.x,a.fxprime);for(var g=0;g<c&&(s(f,a.fxprime,-1),u=o(t,f,a,l,u,x,h),n.history&&(n.history.push({x:a.x.slice(),fx:a.fx,fxprime:a.fxprime.slice(),functionCalls:d,learnRate:u,alpha:u}),d=[]),i=a,a=l,l=i,!(0===u||r(a.fxprime)<1e-5));++g);return a},t.zeros=e,t.zerosM=function(t,n){return e(t).map(function(){return e(n)})},t.norm2=r,t.weightedSum=i,t.scale=s}(e)}(u={path:c,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&u.path)}},u.exports),u.exports);function x(t,e={}){e.maxIterations=e.maxIterations||500;const n=e.initialLayout||p,r=e.lossFunction||y,s=function(t){const e=t.slice(),n=[],r=new Set;function s(t,e){return`${t}-${e}`}for(const t of e)if(1===t.sets.length)n.push(t.sets[0]);else if(2===t.sets.length){const e=t.sets[0],n=t.sets[1];r.add(s(e,n)),r.add(s(n,e))}n.sort((t,e)=>t===e?0:t<e?-1:1);for(let t=0;t<n.length;++t){const i=n[t];for(let o=t+1;o<n.length;++o){const t=n[o];r.has(s(i,t))||e.push({sets:[i,t],size:0})}}return e}(t),i=n(s,e),o=Object.keys(i),a=[];for(const t of o)a.push(i[t].x),a.push(i[t].y);const l=f.nelderMead(t=>{const e={};for(let n=0;n<o.length;++n){const r=o[n];e[r]={x:t[2*n],y:t[2*n+1],radius:i[r].radius}}return r(e,s)},a,e).x;for(let t=0;t<o.length;++t){const e=o[t];i[e].x=l[2*t],i[e].y=l[2*t+1]}return i}const h=1e-10;function d(t,e,n){return Math.min(t,e)*Math.min(t,e)*Math.PI<=n+h?Math.abs(t-e):f.bisect(r=>o(t,e,r)-n,0,t+e)}function p(t,e={}){let n=g(t,e);const r=e.lossFunction||y;if(t.length>=8){const s=function(t,e={}){const n=e.restarts||10,r=[],s={};for(const e of t)1===e.sets.length&&(s[e.sets[0]]=r.length,r.push(e));let{distances:i,constraints:o}=function(t,e,n){const r=f.zerosM(e.length,e.length),s=f.zerosM(e.length,e.length);return t.filter(t=>2===t.sets.length).forEach(t=>{const i=n[t.sets[0]],o=n[t.sets[1]],a=d(Math.sqrt(e[i].size/Math.PI),Math.sqrt(e[o].size/Math.PI),t.size);r[i][o]=r[o][i]=a;let l=0;t.size+1e-10>=Math.min(e[i].size,e[o].size)?l=1:t.size<=1e-10&&(l=-1),s[i][o]=s[o][i]=l}),{distances:r,constraints:s}}(t,r,s);const a=f.norm2(i.map(f.norm2))/i.length;i=i.map(t=>t.map(t=>t/a));const l=(t,e)=>(function(t,e,n,r){for(let t=0;t<e.length;++t)e[t]=0;let s=0;for(let i=0;i<n.length;++i){const o=t[2*i],a=t[2*i+1];for(let l=i+1;l<n.length;++l){const c=t[2*l],u=t[2*l+1],f=n[i][l],x=r[i][l],h=(c-o)*(c-o)+(u-a)*(u-a),d=Math.sqrt(h),p=h-f*f;x>0&&d<=f||x<0&&d>=f||(s+=2*p*p,e[2*i]+=4*p*(o-c),e[2*i+1]+=4*p*(a-u),e[2*l]+=4*p*(c-o),e[2*l+1]+=4*p*(u-a))}}return s})(t,e,i,o);let c=null;for(let t=0;t<n;++t){const t=f.zeros(2*i.length).map(Math.random),n=f.conjugateGradient(l,t,e);(!c||n.fx<c.fx)&&(c=n)}const u=c.x,x={};for(let t=0;t<r.length;++t){const e=r[t];x[e.sets[0]]={x:u[2*t]*a,y:u[2*t+1]*a,radius:Math.sqrt(e.size/Math.PI)}}if(e.history)for(const t of e.history)f.scale(t.x,a);return x}(t,e);r(s,t)+1e-8<r(n,t)&&(n=s)}return n}function g(t,e){const n=e&&e.lossFunction?e.lossFunction:y,r={},s={};for(const e of t)if(1===e.sets.length){const t=e.sets[0];r[t]={x:1e10,y:1e10,rowid:r.length,size:e.size,radius:Math.sqrt(e.size/Math.PI)},s[t]=[]}t=t.filter(t=>2===t.sets.length);for(const e of t){let t=null!=e.weight?e.weight:1;const n=e.sets[0],i=e.sets[1];e.size+h>=Math.min(r[n].size,r[i].size)&&(t=0),s[n].push({set:i,size:e.size,weight:t}),s[i].push({set:n,size:e.size,weight:t})}const i=[];function o(t,e){return e.size-t.size}Object.keys(s).forEach(t=>{let e=0;for(let n=0;n<s[t].length;++n)e+=s[t][n].size*s[t][n].weight;i.push({set:t,size:e})}),i.sort(o);const l={};function c(t){return t.set in l}function u(t,e){r[e].x=t.x,r[e].y=t.y,l[e]=!0}u({x:0,y:0},i[0].set);for(let e=1;e<i.length;++e){const l=i[e].set,x=s[l].filter(c),h=r[l];if(x.sort(o),0===x.length)throw"ERROR: missing pairwise overlap information";const p=[];for(var f=0;f<x.length;++f){const t=r[x[f].set],e=d(h.radius,t.radius,x[f].size);p.push({x:t.x+e,y:t.y}),p.push({x:t.x-e,y:t.y}),p.push({y:t.y+e,x:t.x}),p.push({y:t.y-e,x:t.x});for(let n=f+1;n<x.length;++n){const s=r[x[n].set],i=d(h.radius,s.radius,x[n].size),o=a({x:t.x,y:t.y,radius:e},{x:s.x,y:s.y,radius:i});p.push(...o)}}let g=1e50,y=p[0];for(const e of p){r[l].x=e.x,r[l].y=e.y;const s=n(r,t);s<g&&(g=s,y=e)}u(y,l)}return r}function y(t,e){let n=0;for(const s of e){if(1===s.sets.length)continue;let e;if(2===s.sets.length){const n=t[s.sets[0]],r=t[s.sets[1]];e=o(n.radius,r.radius,i(n,r))}else e=r(s.sets.map(e=>t[e]));n+=(null!=s.weight?s.weight:1)*(e-s.size)*(e-s.size)}return n}function m(t,e,n){if(null==n?t.sort((t,e)=>e.radius-t.radius):t.sort(n),t.length>0){const e=t[0].x,n=t[0].y;for(const r of t)r.x-=e,r.y-=n}if(2===t.length){i(t[0],t[1])<Math.abs(t[1].radius-t[0].radius)&&(t[1].x=t[0].x+t[0].radius-t[1].radius-1e-10,t[1].y=t[0].y)}if(t.length>1){const n=Math.atan2(t[1].x,t[1].y)-e,r=Math.cos(n),s=Math.sin(n);for(const e of t){const t=e.x,n=e.y;e.x=r*t-s*n,e.y=s*t+r*n}}if(t.length>2){let n=Math.atan2(t[2].x,t[2].y)-e;for(;n<0;)n+=2*Math.PI;for(;n>2*Math.PI;)n-=2*Math.PI;if(n>Math.PI){const e=t[1].y/(1e-10+t[1].x);for(const n of t){var r=(n.x+e*n.y)/(1+e*e);n.x=2*r-n.x,n.y=2*r*e-n.y}}}}function M(t){function e(t){return t.parent!==t&&(t.parent=e(t.parent)),t.parent}function n(t,n){const r=e(t),s=e(n);r.parent=s}t.forEach(t=>{t.parent=t});for(let e=0;e<t.length;++e)for(let r=e+1;r<t.length;++r){const s=t[e].radius+t[r].radius;i(t[e],t[r])+1e-10<s&&n(t[r],t[e])}const r=new Map;for(let n=0;n<t.length;++n){const s=e(t[n]).parent.setid;r.has(s)||r.set(s,[]),r.get(s).push(t[n])}return t.forEach(t=>{delete t.parent}),Array.from(r.values())}function v(t){const e=e=>{return{max:t.reduce((t,n)=>Math.max(t,n[e]+n.radius),Number.NEGATIVE_INFINITY),min:t.reduce((t,n)=>Math.min(t,n[e]-n.radius),Number.POSITIVE_INFINITY)}};return{xRange:e("x"),yRange:e("y")}}function b(t,e,n){null==e&&(e=Math.PI/2);let r=w(t).map(t=>Object.assign({},t));const s=M(r);for(const t of s){m(t,e,n);const r=v(t);t.size=(r.xRange.max-r.xRange.min)*(r.yRange.max-r.yRange.min),t.bounds=r}s.sort((t,e)=>e.size-t.size);let i=(r=s[0]).bounds;const o=(i.xRange.max-i.xRange.min)/50;function a(t,e,n){if(!t)return;const s=t.bounds;let a,l;if(e)a=i.xRange.max-s.xRange.min+o;else{a=i.xRange.max-s.xRange.max;const t=(s.xRange.max-s.xRange.min)/2-(i.xRange.max-i.xRange.min)/2;t<0&&(a+=t)}if(n)l=i.yRange.max-s.yRange.min+o;else{l=i.yRange.max-s.yRange.max;const t=(s.yRange.max-s.yRange.min)/2-(i.yRange.max-i.yRange.min)/2;t<0&&(l+=t)}for(const e of t)e.x+=a,e.y+=l,r.push(e)}let l=1;for(;l<s.length;)a(s[l],!0,!1),a(s[l+1],!1,!0),a(s[l+2],!0,!0),l+=3,i=v(r);return I(r)}function z(t,e,n,r,s){const i=w(t);e-=2*r,n-=2*r;const{xRange:o,yRange:a}=v(i);if(o.max===o.min||a.max===a.min)return console.log("not scaling solution: zero size detected"),t;let l,c;if(s){const t=2*Math.sqrt(s/Math.PI);l=e/t,c=n/t}else l=e/(o.max-o.min),c=n/(a.max-a.min);const u=Math.min(c,l),f=(e-(o.max-o.min)*u)/2,x=(n-(a.max-a.min)*u)/2;return I(i.map(t=>({radius:u*t.radius,x:r+f+(t.x-o.min)*u,y:r+x+(t.y-a.min)*u,setid:t.setid})))}function I(t){const e={};for(const n of t)e[n.setid]=n;return e}function w(t){return Object.keys(t).map(e=>Object.assign(t[e],{setid:e}))}function R(t,n){return function(){const r=e.select(this),s=r.datum(),i=t[s.sets[0]].radius||50,o=n(s)||"",a=o.split(/\s+/).reverse(),l=(o.length+a.length)/3;let c=a.pop();const u=[c];let f=0;let x=r.text(null).append("tspan").text(c);for(;c=a.pop();){u.push(c);const t=u.join(" ");x.text(t),t.length>l&&x.node().getComputedTextLength()>i&&(u.pop(),x.text(u.join(" ")),u=[c],x=r.append("tspan").text(c),f++)}const h=.35-1.1*f/2,d=r.attr("x"),p=r.attr("y");r.selectAll("tspan").attr("x",d).attr("y",p).attr("dy",(t,e)=>`${h+1.1*e}em`)}}function F(t,e,n){let r=e[0].radius-i(e[0],t);for(let n=1;n<e.length;++n){const s=e[n].radius-i(e[n],t);s<=r&&(r=s)}for(let e=0;e<n.length;++e){const s=i(n[e],t)-n[e].radius;s<=r&&(r=s)}return r}function A(t,e,n){const s=[];for(const e of t)s.push({x:e.x,y:e.y}),s.push({x:e.x+e.radius/2,y:e.y}),s.push({x:e.x-e.radius/2,y:e.y}),s.push({x:e.x,y:e.y+e.radius/2}),s.push({x:e.x,y:e.y-e.radius/2});let o=s[0],a=F(s[0],t,e);for(let n=1;n<s.length;++n){const r=F(s[n],t,e);r>=a&&(o=s[n],a=r)}const c=f.nelderMead(n=>-1*F({x:n[0],y:n[1]},t,e),[o.x,o.y],{maxIterations:500,minErrorDelta:1e-10}).x,u={x:n?0:c[0],y:c[1]};let x=!0;for(const e of t)if(i(u,e)>e.radius){x=!1;break}for(const t of e)if(i(u,t)<t.radius){x=!1;break}if(x)return u;if(1==t.length)return{x:t[0].x,y:t[0].y};const h={};return r(t,h),0===h.arcs.length?{x:0,y:-1e3,disjoint:!0}:1==h.arcs.length?{x:h.arcs[0].circle.x,y:h.arcs[0].circle.y}:e.length?A(t,[]):l(h.arcs.map(t=>t.p1))}function P(t){const e={},n=Object.keys(t);for(const t of n)e[t]=[];for(let r=0;r<n.length;r++){const s=n[r],o=t[s];for(let a=r+1;a<n.length;++a){const r=n[a],l=t[r],c=i(o,l);c+l.radius<=o.radius+1e-10?e[r].push(s):c+o.radius<=l.radius+1e-10&&e[s].push(r)}}return e}function j(t,e,n){const r={},s=P(t);for(let i=0;i<e.length;++i){const o=e[i].sets,a={},l={};for(let t=0;t<o.length;++t){a[o[t]]=!0;const e=s[o[t]];for(let t=0;t<e.length;++t)l[e[t]]=!0}const c=[],u=[];for(let e in t)e in a?c.push(t[e]):e in l||u.push(t[e]);const f=A(c,u,n);r[o]=f,f.disjoint&&e[i].size>0&&console.log("WARNING: area "+o+" not represented on screen")}return r}function T(t,e,n){const r=[];return r.push("\nM",t,e),r.push("\nm",-n,0),r.push("\na",n,n,0,1,0,2*n,0),r.push("\na",n,n,0,1,0,2*-n,0),r.join(" ")}function q(t){const e=t.split(" ");return{x:Number.parseFloat(e[1]),y:Number.parseFloat(e[2]),radius:-Number.parseFloat(e[4])}}function E(t){if(0===t.length)return[];const e={};return r(t,e),e.arcs}function O(t){if(0===t.length)return"M 0 0";if(1==t.length){const e=t[0].circle;return T(e.x,e.y,e.radius)}const e=["\nM",t[0].p2.x,t[0].p2.y];for(const n of t){const t=n.circle.radius,r=n.width>t;e.push("\nA",t,t,0,r?1:0,1,n.p1.x,n.p1.y)}return e.join(" ")}function k(t){return O(E(t))}t.VennDiagram=function(t={}){let n=!1,r=600,s=350,i=15,o=1e3,a=Math.PI/2,l=!0,c=null,u=!0,f=!0,h=null,d=null,p=!(!t||!t.symmetricalTextCentre)&&t.symmetricalTextCentre,g={},m=t&&t.colourScheme?t.colourScheme:["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"],M=0,v=function(t){if(t in g)return g[t];var e=g[t]=m[M];return(M+=1)>=m.length&&(M=0),e},I=x,w=y;function F(x){let g=x.datum();const y=new Set;g.forEach(t=>{0==t.size&&1==t.sets.length&&y.add(t.sets[0])}),g=g.filter(t=>!t.sets.some(t=>y.has(t)));let m={},M={};if(g.length>0){let t=I(g,{lossFunction:w});l&&(t=b(t,a,d)),m=z(t,r,s,i,c),M=j(m,g,p)}const F={};function A(t){return t.sets in F?F[t.sets]:1==t.sets.length?""+t.sets[0]:void 0}g.forEach(t=>{t.label&&(F[t.sets]=t.label)}),x.selectAll("svg").data([m]).enter().append("svg");const P=x.select("svg");n?P.attr("viewBox",`0 0 ${r} ${s}`):P.attr("width",r).attr("height",s);const T={};let E=!1;function O(t){return e=>k(t.sets.map(t=>{let n=T[t],i=m[t];return n||(n={x:r/2,y:s/2,radius:1}),i||(i={x:r/2,y:s/2,radius:1}),{x:n.x*(1-e)+i.x*e,y:n.y*(1-e)+i.y*e,radius:n.radius*(1-e)+i.radius*e}}))}P.selectAll(".venn-area path").each(function(t){var n=e.select(this).attr("d");1==t.sets.length&&n&&(E=!0,T[t.sets[0]]=q(n))});const N=P.selectAll(".venn-area").data(g,t=>t.sets),S=N.enter().append("g").attr("class",t=>`venn-area venn-${1==t.sets.length?"circle":"intersection"}${t.colour?" venn-coloured":""}`).attr("data-venn-sets",t=>t.sets.join("_")),C=S.append("path"),D=S.append("text").attr("class","label").text(t=>A(t)).attr("text-anchor","middle").attr("dy",".35em").attr("x",r/2).attr("y",s/2);f&&(C.style("fill-opacity","0").filter(t=>1==t.sets.length).style("fill",t=>t.colour?t.colour:v(t.sets)).style("fill-opacity",".25"),D.style("fill",e=>e.colour?"#FFF":t.textFill?t.textFill:1==e.sets.length?v(e.sets):"#444"));let $=x;E?($=x.transition("venn").duration(o)).selectAll("path").attrTween("d",O):$.selectAll("path").attr("d",t=>k(t.sets.map(t=>m[t])));const L=$.selectAll("text").filter(t=>t.sets in M).text(t=>A(t)).attr("x",t=>Math.floor(M[t.sets].x)).attr("y",t=>Math.floor(M[t.sets].y));u&&(E?"on"in L?L.on("end",R(m,A)):L.each("end",R(m,A)):L.each(R(m,A)));const V=N.exit().transition("venn").duration(o).remove();V.selectAll("path").attrTween("d",O);const _=V.selectAll("text").attr("x",r/2).attr("y",s/2);return null!==h&&(D.style("font-size","0px"),L.style("font-size",h),_.style("font-size","0px")),{circles:m,textCentres:M,nodes:N,enter:S,update:$,exit:V}}return F.wrap=function(t){return arguments.length?(u=t,F):u},F.useViewBox=function(){return n=!0,F},F.width=function(t){return arguments.length?(r=t,F):r},F.height=function(t){return arguments.length?(s=t,F):s},F.padding=function(t){return arguments.length?(i=t,F):i},F.colours=function(t){return arguments.length?(v=t,F):v},F.fontSize=function(t){return arguments.length?(h=t,F):h},F.duration=function(t){return arguments.length?(o=t,F):o},F.layoutFunction=function(t){return arguments.length?(I=t,F):I},F.normalize=function(t){return arguments.length?(l=t,F):l},F.scaleToFit=function(t){return arguments.length?(c=t,F):c},F.styled=function(t){return arguments.length?(f=t,F):f},F.orientation=function(t){return arguments.length?(a=t,F):a},F.orientationOrder=function(t){return arguments.length?(d=t,F):d},F.lossFunction=function(t){return arguments.length?(w=t,F):w},F},t.bestInitialLayout=p,t.circleArea=s,t.circleCircleIntersection=a,t.circleFromPath=q,t.circleOverlap=o,t.circlePath=T,t.computeTextCentre=A,t.computeTextCentres=j,t.computeVennLayout=function(t,e={}){const{lossFunction:n=n,layoutFunction:r=r,normalize:s=!0,orientation:i=Math.PI/2,orientationOrder:o,width:a=600,height:l=350,padding:c=15,scaleToFit:u=!1,symmetricalTextCentre:f=!1}=e;let x=r(t,{lossFunction:n});s&&(x=b(x,i,o));const h=z(x,a,l,c,u),d=j(h,t,f),p=new Map(Object.keys(h).map(t=>[t,{set:t,x:h[t].x,y:h[t].y,radius:h[t].radius,text:d[t]}]));return t.map(e=>{const n=e.sets.map(t=>p.get(t)),r=E(n);return{data:t,circles:n,arcs:r,path:O(r)}})},t.disjointCluster=M,t.distance=i,t.distanceFromIntersectArea=d,t.greedyLayout=g,t.intersectionArea=r,t.intersectionAreaPath=k,t.lossFunction=y,t.normalizeSolution=b,t.scaleSolution=z,t.sortAreas=function(t,e){const n=P(t.selectAll("svg").datum()),r=new Set;for(const t of e.sets)for(let e in n){const s=n[e];for(let n=0;n<s.length;++n)if(s[n]==t){r.add(e);break}}function s(t){return t.every(t=>!r.has(t))}t.selectAll("g").sort((t,n)=>t.sets.length!=n.sets.length?t.sets.length-n.sets.length:t==e?s(n.sets)?-1:1:n==e?s(t.sets)?1:-1:n.size-t.size)},t.venn=x,t.wrapText=R,Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).venn={})}(this,function(t){"use strict";const e=1e-10;function n(t,n){const i=function(t){const e=[];for(let n=0;n<t.length;++n)for(let r=n+1;r<t.length;++r){const s=o(t[n],t[r]);for(const t of s)t.parentIndex=[n,r],e.push(t)}return e}(t),l=i.filter(n=>(function(t,n){return n.every(n=>s(t,n)<n.radius+e)})(n,t));let c=0,u=0;const f=[];if(l.length>1){const e=a(l);for(let t=0;t<l.length;++t){const n=l[t];n.angle=Math.atan2(n.x-e.x,n.y-e.y)}l.sort((t,e)=>e.angle-t.angle);let n=l[l.length-1];for(let e=0;e<l.length;++e){const i=l[e];u+=(n.x+i.x)*(i.y-n.y);const o={x:(i.x+n.x)/2,y:(i.y+n.y)/2};let a=null;for(let e=0;e<i.parentIndex.length;++e)if(n.parentIndex.includes(i.parentIndex[e])){const r=t[i.parentIndex[e]],l=Math.atan2(i.x-r.x,i.y-r.y),c=Math.atan2(n.x-r.x,n.y-r.y);let u=c-l;u<0&&(u+=2*Math.PI);const f=c-u/2;let x=s(o,{x:r.x+r.radius*Math.sin(f),y:r.y+r.radius*Math.cos(f)});x>2*r.radius&&(x=2*r.radius),(null==a||a.width>x)&&(a={circle:r,width:x,p1:i,p2:n})}null!=a&&(f.push(a),c+=r(a.circle.radius,a.width),n=i)}}else{let n=t[0];for(let e=1;e<t.length;++e)t[e].radius<n.radius&&(n=t[e]);let r=!1;for(let e=0;e<t.length;++e)if(s(t[e],n)>Math.abs(n.radius-t[e].radius)){r=!0;break}r?c=u=0:(c=n.radius*n.radius*Math.PI,f.push({circle:n,p1:{x:n.x,y:n.y+n.radius},p2:{x:n.x-e,y:n.y+n.radius},width:2*n.radius}))}return u/=2,n&&(n.area=c+u,n.arcArea=c,n.polygonArea=u,n.arcs=f,n.innerPoints=l,n.intersectionPoints=i),c+u}function r(t,e){return t*t*Math.acos(1-e/t)-(t-e)*Math.sqrt(e*(2*t-e))}function s(t,e){return Math.sqrt((t.x-e.x)*(t.x-e.x)+(t.y-e.y)*(t.y-e.y))}function i(t,e,n){if(n>=t+e)return 0;if(n<=Math.abs(t-e))return Math.PI*Math.min(t,e)*Math.min(t,e);const s=e-(n*n-t*t+e*e)/(2*n);return r(t,t-(n*n-e*e+t*t)/(2*n))+r(e,s)}function o(t,e){const n=s(t,e),r=t.radius,i=e.radius;if(n>=r+i||n<=Math.abs(r-i))return[];const o=(r*r-i*i+n*n)/(2*n),a=Math.sqrt(r*r-o*o),l=t.x+o*(e.x-t.x)/n,c=t.y+o*(e.y-t.y)/n,u=-(e.y-t.y)*(a/n),f=-(e.x-t.x)*(a/n);return[{x:l+u,y:c-f},{x:l-u,y:c+f}]}function a(t){const e={x:0,y:0};for(const n of t)e.x+=n.x,e.y+=n.y;return e.x/=t.length,e.y/=t.length,e}"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var l,c,u=(function(t,e){!function(t){function e(t){for(var e=new Array(t),n=0;n<t;++n)e[n]=0;return e}function n(t,e){for(var n=0,r=0;r<t.length;++r)n+=t[r]*e[r];return n}function r(t){return Math.sqrt(n(t,t))}function s(t,e,n){for(var r=0;r<e.length;++r)t[r]=e[r]*n}function i(t,e,n,r,s){for(var i=0;i<t.length;++i)t[i]=e*n[i]+r*s[i]}function o(t,e,r,s,o,a,l){var c=r.fx,u=n(r.fxprime,e),f=c,x=c,h=u,p=0;function d(x,p,d){for(var g=0;g<16;++g)if(o=(x+p)/2,i(s.x,1,r.x,o,e),f=s.fx=t(s.x,s.fxprime),h=n(s.fxprime,e),f>c+a*o*u||f>=d)p=o;else{if(Math.abs(h)<=-l*u)return o;h*(p-x)>=0&&(p=x),x=o,d=f}return 0}o=o||1,a=a||1e-6,l=l||.1;for(var g=0;g<10;++g){if(i(s.x,1,r.x,o,e),f=s.fx=t(s.x,s.fxprime),h=n(s.fxprime,e),f>c+a*o*u||g&&f>=x)return d(p,o,x);if(Math.abs(h)<=-l*u)return o;if(h>=0)return d(o,p,f);x=f,p=o,o*=2}return o}t.bisect=function(t,e,n,r){var s=(r=r||{}).maxIterations||100,i=r.tolerance||1e-10,o=t(e),a=t(n),l=n-e;if(o*a>0)throw"Initial bisect points must have opposite signs";if(0===o)return e;if(0===a)return n;for(var c=0;c<s;++c){var u=e+(l/=2),f=t(u);if(f*o>=0&&(e=u),Math.abs(l)<i||0===f)return u}return e+l},t.nelderMead=function(t,e,n){var r,s=(n=n||{}).maxIterations||200*e.length,o=n.nonZeroDelta||1.05,a=n.zeroDelta||.001,l=n.minErrorDelta||1e-6,c=n.minErrorDelta||1e-5,u=void 0!==n.rho?n.rho:1,f=void 0!==n.chi?n.chi:2,x=void 0!==n.psi?n.psi:-.5,h=void 0!==n.sigma?n.sigma:.5,p=e.length,d=new Array(p+1);d[0]=e,d[0].fx=t(e),d[0].id=0;for(var g=0;g<p;++g){var y=e.slice();y[g]=y[g]?y[g]*o:a,d[g+1]=y,d[g+1].fx=t(y),d[g+1].id=g+1}function m(t){for(var e=0;e<t.length;e++)d[p][e]=t[e];d[p].fx=t.fx}for(var M=function(t,e){return t.fx-e.fx},v=e.slice(),b=e.slice(),z=e.slice(),I=e.slice(),w=0;w<s;++w){if(d.sort(M),n.history){var R=d.map(function(t){var e=t.slice();return e.fx=t.fx,e.id=t.id,e});R.sort(function(t,e){return t.id-e.id}),n.history.push({x:d[0].slice(),fx:d[0].fx,simplex:R})}for(r=0,g=0;g<p;++g)r=Math.max(r,Math.abs(d[0][g]-d[1][g]));if(Math.abs(d[0].fx-d[p].fx)<l&&r<c)break;for(g=0;g<p;++g){v[g]=0;for(var A=0;A<p;++A)v[g]+=d[A][g];v[g]/=p}var F=d[p];if(i(b,1+u,v,-u,F),b.fx=t(b),b.fx<d[0].fx)i(I,1+f,v,-f,F),I.fx=t(I),I.fx<b.fx?m(I):m(b);else if(b.fx>=d[p-1].fx){var P=!1;if(b.fx>F.fx?(i(z,1+x,v,-x,F),z.fx=t(z),z.fx<F.fx?m(z):P=!0):(i(z,1-x*u,v,x*u,F),z.fx=t(z),z.fx<b.fx?m(z):P=!0),P){if(h>=1)break;for(g=1;g<d.length;++g)i(d[g],1-h,d[0],h,d[g]),d[g].fx=t(d[g])}}else m(b)}return d.sort(M),{fx:d[0].fx,x:d[0]}},t.conjugateGradient=function(t,e,a){var l,c,u,f={x:e.slice(),fx:0,fxprime:e.slice()},x={x:e.slice(),fx:0,fxprime:e.slice()},h=e.slice(),p=1;u=(a=a||{}).maxIterations||20*e.length,f.fx=t(f.x,f.fxprime),s(l=f.fxprime.slice(),f.fxprime,-1);for(var d=0;d<u;++d){if(p=o(t,l,f,x,p),a.history&&a.history.push({x:f.x.slice(),fx:f.fx,fxprime:f.fxprime.slice(),alpha:p}),p){i(h,1,x.fxprime,-1,f.fxprime);var g=n(f.fxprime,f.fxprime),y=Math.max(0,n(h,x.fxprime)/g);i(l,y,l,-1,x.fxprime),c=f,f=x,x=c}else s(l,f.fxprime,-1);if(r(f.fxprime)<=1e-5)break}return a.history&&a.history.push({x:f.x.slice(),fx:f.fx,fxprime:f.fxprime.slice(),alpha:p}),f},t.gradientDescent=function(t,e,n){for(var s=(n=n||{}).maxIterations||100*e.length,o=n.learnRate||.001,a={x:e.slice(),fx:0,fxprime:e.slice()},l=0;l<s&&(a.fx=t(a.x,a.fxprime),n.history&&n.history.push({x:a.x.slice(),fx:a.fx,fxprime:a.fxprime.slice()}),i(a.x,1,a.x,-o,a.fxprime),!(r(a.fxprime)<=1e-5));++l);return a},t.gradientDescentLineSearch=function(t,e,n){n=n||{};var i,a={x:e.slice(),fx:0,fxprime:e.slice()},l={x:e.slice(),fx:0,fxprime:e.slice()},c=n.maxIterations||100*e.length,u=n.learnRate||1,f=e.slice(),x=n.c1||.001,h=n.c2||.1,p=[];if(n.history){var d=t;t=function(t,e){return p.push(t.slice()),d(t,e)}}a.fx=t(a.x,a.fxprime);for(var g=0;g<c&&(s(f,a.fxprime,-1),u=o(t,f,a,l,u,x,h),n.history&&(n.history.push({x:a.x.slice(),fx:a.fx,fxprime:a.fxprime.slice(),functionCalls:p,learnRate:u,alpha:u}),p=[]),i=a,a=l,l=i,!(0===u||r(a.fxprime)<1e-5));++g);return a},t.zeros=e,t.zerosM=function(t,n){return e(t).map(function(){return e(n)})},t.norm2=r,t.weightedSum=i,t.scale=s}(e)}(c={path:l,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&c.path)}},c.exports),c.exports);function f(t,e={}){e.maxIterations=e.maxIterations||500;const n=e.initialLayout||p,r=e.lossFunction||g,s=function(t){const e=t.slice(),n=[],r=new Set;function s(t,e){return`${t}-${e}`}for(const t of e)if(1===t.sets.length)n.push(t.sets[0]);else if(2===t.sets.length){const e=t.sets[0],n=t.sets[1];r.add(s(e,n)),r.add(s(n,e))}n.sort((t,e)=>t===e?0:t<e?-1:1);for(let t=0;t<n.length;++t){const i=n[t];for(let o=t+1;o<n.length;++o){const t=n[o];r.has(s(i,t))||e.push({sets:[i,t],size:0})}}return e}(t),i=n(s,e),o=Object.keys(i),a=[];for(const t of o)a.push(i[t].x),a.push(i[t].y);const l=u.nelderMead(t=>{const e={};for(let n=0;n<o.length;++n){const r=o[n];e[r]={x:t[2*n],y:t[2*n+1],radius:i[r].radius}}return r(e,s)},a,e).x;for(let t=0;t<o.length;++t){const e=o[t];i[e].x=l[2*t],i[e].y=l[2*t+1]}return i}const x=1e-10;function h(t,e,n){return Math.min(t,e)*Math.min(t,e)*Math.PI<=n+x?Math.abs(t-e):u.bisect(r=>i(t,e,r)-n,0,t+e)}function p(t,e={}){let n=d(t,e);const r=e.lossFunction||g;if(t.length>=8){const s=function(t,e={}){const n=e.restarts||10,r=[],s={};for(const e of t)1===e.sets.length&&(s[e.sets[0]]=r.length,r.push(e));let{distances:i,constraints:o}=function(t,e,n){const r=u.zerosM(e.length,e.length),s=u.zerosM(e.length,e.length);return t.filter(t=>2===t.sets.length).forEach(t=>{const i=n[t.sets[0]],o=n[t.sets[1]],a=h(Math.sqrt(e[i].size/Math.PI),Math.sqrt(e[o].size/Math.PI),t.size);r[i][o]=r[o][i]=a;let l=0;t.size+1e-10>=Math.min(e[i].size,e[o].size)?l=1:t.size<=1e-10&&(l=-1),s[i][o]=s[o][i]=l}),{distances:r,constraints:s}}(t,r,s);const a=u.norm2(i.map(u.norm2))/i.length;i=i.map(t=>t.map(t=>t/a));const l=(t,e)=>(function(t,e,n,r){for(let t=0;t<e.length;++t)e[t]=0;let s=0;for(let i=0;i<n.length;++i){const o=t[2*i],a=t[2*i+1];for(let l=i+1;l<n.length;++l){const c=t[2*l],u=t[2*l+1],f=n[i][l],x=r[i][l],h=(c-o)*(c-o)+(u-a)*(u-a),p=Math.sqrt(h),d=h-f*f;x>0&&p<=f||x<0&&p>=f||(s+=2*d*d,e[2*i]+=4*d*(o-c),e[2*i+1]+=4*d*(a-u),e[2*l]+=4*d*(c-o),e[2*l+1]+=4*d*(u-a))}}return s})(t,e,i,o);let c=null;for(let t=0;t<n;++t){const t=u.zeros(2*i.length).map(Math.random),n=u.conjugateGradient(l,t,e);(!c||n.fx<c.fx)&&(c=n)}const f=c.x,x={};for(let t=0;t<r.length;++t){const e=r[t];x[e.sets[0]]={x:f[2*t]*a,y:f[2*t+1]*a,radius:Math.sqrt(e.size/Math.PI)}}if(e.history)for(const t of e.history)u.scale(t.x,a);return x}(t,e);r(s,t)+1e-8<r(n,t)&&(n=s)}return n}function d(t,e){const n=e&&e.lossFunction?e.lossFunction:g,r={},s={};for(const e of t)if(1===e.sets.length){const t=e.sets[0];r[t]={x:1e10,y:1e10,rowid:r.length,size:e.size,radius:Math.sqrt(e.size/Math.PI)},s[t]=[]}t=t.filter(t=>2===t.sets.length);for(const e of t){let t=null!=e.weight?e.weight:1;const n=e.sets[0],i=e.sets[1];e.size+x>=Math.min(r[n].size,r[i].size)&&(t=0),s[n].push({set:i,size:e.size,weight:t}),s[i].push({set:n,size:e.size,weight:t})}const i=[];function a(t,e){return e.size-t.size}Object.keys(s).forEach(t=>{let e=0;for(let n=0;n<s[t].length;++n)e+=s[t][n].size*s[t][n].weight;i.push({set:t,size:e})}),i.sort(a);const l={};function c(t){return t.set in l}function u(t,e){r[e].x=t.x,r[e].y=t.y,l[e]=!0}u({x:0,y:0},i[0].set);for(let e=1;e<i.length;++e){const l=i[e].set,x=s[l].filter(c),p=r[l];if(x.sort(a),0===x.length)throw"ERROR: missing pairwise overlap information";const d=[];for(var f=0;f<x.length;++f){const t=r[x[f].set],e=h(p.radius,t.radius,x[f].size);d.push({x:t.x+e,y:t.y}),d.push({x:t.x-e,y:t.y}),d.push({y:t.y+e,x:t.x}),d.push({y:t.y-e,x:t.x});for(let n=f+1;n<x.length;++n){const s=r[x[n].set],i=h(p.radius,s.radius,x[n].size),a=o({x:t.x,y:t.y,radius:e},{x:s.x,y:s.y,radius:i});d.push(...a)}}let g=1e50,y=d[0];for(const e of d){r[l].x=e.x,r[l].y=e.y;const s=n(r,t);s<g&&(g=s,y=e)}u(y,l)}return r}function g(t,e){let r=0;for(const o of e){if(1===o.sets.length)continue;let e;if(2===o.sets.length){const n=t[o.sets[0]],r=t[o.sets[1]];e=i(n.radius,r.radius,s(n,r))}else e=n(o.sets.map(e=>t[e]));r+=(null!=o.weight?o.weight:1)*(e-o.size)*(e-o.size)}return r}function y(t,e,n){if(null==n?t.sort((t,e)=>e.radius-t.radius):t.sort(n),t.length>0){const e=t[0].x,n=t[0].y;for(const r of t)r.x-=e,r.y-=n}if(2===t.length){s(t[0],t[1])<Math.abs(t[1].radius-t[0].radius)&&(t[1].x=t[0].x+t[0].radius-t[1].radius-1e-10,t[1].y=t[0].y)}if(t.length>1){const n=Math.atan2(t[1].x,t[1].y)-e,r=Math.cos(n),s=Math.sin(n);for(const e of t){const t=e.x,n=e.y;e.x=r*t-s*n,e.y=s*t+r*n}}if(t.length>2){let n=Math.atan2(t[2].x,t[2].y)-e;for(;n<0;)n+=2*Math.PI;for(;n>2*Math.PI;)n-=2*Math.PI;if(n>Math.PI){const e=t[1].y/(1e-10+t[1].x);for(const n of t){var r=(n.x+e*n.y)/(1+e*e);n.x=2*r-n.x,n.y=2*r*e-n.y}}}}function m(t){function e(t){return t.parent!==t&&(t.parent=e(t.parent)),t.parent}function n(t,n){const r=e(t),s=e(n);r.parent=s}t.forEach(t=>{t.parent=t});for(let e=0;e<t.length;++e)for(let r=e+1;r<t.length;++r){const i=t[e].radius+t[r].radius;s(t[e],t[r])+1e-10<i&&n(t[r],t[e])}const r=new Map;for(let n=0;n<t.length;++n){const s=e(t[n]).parent.setid;r.has(s)||r.set(s,[]),r.get(s).push(t[n])}return t.forEach(t=>{delete t.parent}),Array.from(r.values())}function M(t){const e=e=>{return{max:t.reduce((t,n)=>Math.max(t,n[e]+n.radius),Number.NEGATIVE_INFINITY),min:t.reduce((t,n)=>Math.min(t,n[e]-n.radius),Number.POSITIVE_INFINITY)}};return{xRange:e("x"),yRange:e("y")}}function v(t,e,n){null==e&&(e=Math.PI/2);let r=I(t).map(t=>Object.assign({},t));const s=m(r);for(const t of s){y(t,e,n);const r=M(t);t.size=(r.xRange.max-r.xRange.min)*(r.yRange.max-r.yRange.min),t.bounds=r}s.sort((t,e)=>e.size-t.size);let i=(r=s[0]).bounds;const o=(i.xRange.max-i.xRange.min)/50;function a(t,e,n){if(!t)return;const s=t.bounds;let a,l;if(e)a=i.xRange.max-s.xRange.min+o;else{a=i.xRange.max-s.xRange.max;const t=(s.xRange.max-s.xRange.min)/2-(i.xRange.max-i.xRange.min)/2;t<0&&(a+=t)}if(n)l=i.yRange.max-s.yRange.min+o;else{l=i.yRange.max-s.yRange.max;const t=(s.yRange.max-s.yRange.min)/2-(i.yRange.max-i.yRange.min)/2;t<0&&(l+=t)}for(const e of t)e.x+=a,e.y+=l,r.push(e)}let l=1;for(;l<s.length;)a(s[l],!0,!1),a(s[l+1],!1,!0),a(s[l+2],!0,!0),l+=3,i=M(r);return z(r)}function b(t,e,n,r,s){const i=I(t);e-=2*r,n-=2*r;const{xRange:o,yRange:a}=M(i);if(o.max===o.min||a.max===a.min)return console.log("not scaling solution: zero size detected"),t;let l,c;if(s){const t=2*Math.sqrt(s/Math.PI);l=e/t,c=n/t}else l=e/(o.max-o.min),c=n/(a.max-a.min);const u=Math.min(c,l),f=(e-(o.max-o.min)*u)/2,x=(n-(a.max-a.min)*u)/2;return z(i.map(t=>({radius:u*t.radius,x:r+f+(t.x-o.min)*u,y:r+x+(t.y-a.min)*u,setid:t.setid})))}function z(t){const e={};for(const n of t)e[n.setid]=n;return e}function I(t){return Object.keys(t).map(e=>Object.assign(t[e],{setid:e}))}function w(t,e){return function(n){const r=this,s=t[n.sets[0]].radius||50,i=e(n)||"",o=i.split(/\s+/).reverse(),a=(i.length+o.length)/3;let l=o.pop(),c=[l],u=0;r.textContent=null;const f=[];function x(t){const e=r.ownerDocument.createElementNS(r.namespaceURI,"tspan");return e.textContent=t,f.push(e),r.append(e),e}let h=x(l);for(;l=o.pop();){c.push(l);const t=c.join(" ");h.textContent=t,t.length>a&&h.getComputedTextLength()>s&&(c.pop(),h.textContent=c.join(" "),c=[l],h=x(l),u++)}const p=.35-1.1*u/2,d=r.getAttribute("x"),g=r.getAttribute("y");f.forEach((t,e)=>{t.setAttribute("x",d),t.setAttribute("y",g),t.setAttribute("dy",`${p+1.1*e}em`)})}}function R(t,e,n){let r=e[0].radius-s(e[0],t);for(let n=1;n<e.length;++n){const i=e[n].radius-s(e[n],t);i<=r&&(r=i)}for(let e=0;e<n.length;++e){const i=s(n[e],t)-n[e].radius;i<=r&&(r=i)}return r}function A(t,e,r){const i=[];for(const e of t)i.push({x:e.x,y:e.y}),i.push({x:e.x+e.radius/2,y:e.y}),i.push({x:e.x-e.radius/2,y:e.y}),i.push({x:e.x,y:e.y+e.radius/2}),i.push({x:e.x,y:e.y-e.radius/2});let o=i[0],l=R(i[0],t,e);for(let n=1;n<i.length;++n){const r=R(i[n],t,e);r>=l&&(o=i[n],l=r)}const c=u.nelderMead(n=>-1*R({x:n[0],y:n[1]},t,e),[o.x,o.y],{maxIterations:500,minErrorDelta:1e-10}).x,f={x:r?0:c[0],y:c[1]};let x=!0;for(const e of t)if(s(f,e)>e.radius){x=!1;break}for(const t of e)if(s(f,t)<t.radius){x=!1;break}if(x)return f;if(1==t.length)return{x:t[0].x,y:t[0].y};const h={};return n(t,h),0===h.arcs.length?{x:0,y:-1e3,disjoint:!0}:1==h.arcs.length?{x:h.arcs[0].circle.x,y:h.arcs[0].circle.y}:e.length?A(t,[]):a(h.arcs.map(t=>t.p1))}function F(t){const e={},n=Object.keys(t);for(const t of n)e[t]=[];for(let r=0;r<n.length;r++){const i=n[r],o=t[i];for(let a=r+1;a<n.length;++a){const r=n[a],l=t[r],c=s(o,l);c+l.radius<=o.radius+1e-10?e[r].push(i):c+o.radius<=l.radius+1e-10&&e[i].push(r)}}return e}function P(t,e,n){const r={},s=F(t);for(let i=0;i<e.length;++i){const o=e[i].sets,a={},l={};for(let t=0;t<o.length;++t){a[o[t]]=!0;const e=s[o[t]];for(let t=0;t<e.length;++t)l[e[t]]=!0}const c=[],u=[];for(let e in t)e in a?c.push(t[e]):e in l||u.push(t[e]);const f=A(c,u,n);r[o]=f,f.disjoint&&e[i].size>0&&console.log("WARNING: area "+o+" not represented on screen")}return r}function j(t,e,n){const r=[];return r.push("\nM",t,e),r.push("\nm",-n,0),r.push("\na",n,n,0,1,0,2*n,0),r.push("\na",n,n,0,1,0,2*-n,0),r.join(" ")}function T(t){const e=t.split(" ");return{x:Number.parseFloat(e[1]),y:Number.parseFloat(e[2]),radius:-Number.parseFloat(e[4])}}function E(t){if(0===t.length)return[];const e={};return n(t,e),e.arcs}function C(t){if(0===t.length)return"M 0 0";if(1==t.length){const e=t[0].circle;return j(e.x,e.y,e.radius)}const e=["\nM",t[0].p2.x,t[0].p2.y];for(const n of t){const t=n.circle.radius,r=n.width>t;e.push("\nA",t,t,0,r?1:0,1,n.p1.x,n.p1.y)}return e.join(" ")}function N(t){return C(E(t))}t.VennDiagram=function(t={}){let e=!1,n=600,r=350,s=15,i=1e3,o=Math.PI/2,a=!0,l=null,c=!0,u=!0,x=null,h=null,p=!(!t||!t.symmetricalTextCentre)&&t.symmetricalTextCentre,d={},y=t&&t.colourScheme?t.colourScheme:["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"],m=0,M=function(t){if(t in d)return d[t];var e=d[t]=y[m];return(m+=1)>=y.length&&(m=0),e},z=f,I=g;function R(f){let d=f.datum();const g=new Set;d.forEach(t=>{0==t.size&&1==t.sets.length&&g.add(t.sets[0])}),d=d.filter(t=>!t.sets.some(t=>g.has(t)));let y={},m={};if(d.length>0){let t=z(d,{lossFunction:I});a&&(t=v(t,o,h)),y=b(t,n,r,s,l),m=P(y,d,p)}const R={};function A(t){return t.sets in R?R[t.sets]:1==t.sets.length?""+t.sets[0]:void 0}d.forEach(t=>{t.label&&(R[t.sets]=t.label)}),f.selectAll("svg").data([y]).enter().append("svg");const F=f.select("svg");e?F.attr("viewBox",`0 0 ${n} ${r}`):F.attr("width",n).attr("height",r);const j={};let E=!1;function C(t){return e=>N(t.sets.map(t=>{let s=j[t],i=y[t];return s||(s={x:n/2,y:r/2,radius:1}),i||(i={x:n/2,y:r/2,radius:1}),{x:s.x*(1-e)+i.x*e,y:s.y*(1-e)+i.y*e,radius:s.radius*(1-e)+i.radius*e}}))}F.selectAll(".venn-area path").each(function(t){const e=this.getAttribute("d");1==t.sets.length&&e&&(E=!0,j[t.sets[0]]=T(e))});const O=F.selectAll(".venn-area").data(d,t=>t.sets),k=O.enter().append("g").attr("class",t=>`venn-area venn-${1==t.sets.length?"circle":"intersection"}${t.colour?" venn-coloured":""}`).attr("data-venn-sets",t=>t.sets.join("_")),q=k.append("path"),S=k.append("text").attr("class","label").text(t=>A(t)).attr("text-anchor","middle").attr("dy",".35em").attr("x",n/2).attr("y",r/2);function D(t){return"function"==typeof t.transition?t.transition("venn").duration(i):t}u&&(q.style("fill-opacity","0").filter(t=>1==t.sets.length).style("fill",t=>t.colour?t.colour:M(t.sets)).style("fill-opacity",".25"),S.style("fill",e=>e.colour?"#FFF":t.textFill?t.textFill:1==e.sets.length?M(e.sets):"#444"));let $=f;E?($=D(f)).selectAll("path").attrTween("d",C):$.selectAll("path").attr("d",t=>N(t.sets.map(t=>y[t])));const L=$.selectAll("text").filter(t=>t.sets in m).text(t=>A(t)).attr("x",t=>Math.floor(m[t.sets].x)).attr("y",t=>Math.floor(m[t.sets].y));c&&(E?"on"in L?L.on("end",w(y,A)):L.each("end",w(y,A)):L.each(w(y,A)));const _=D(O.exit()).remove();_.selectAll("path").attrTween("d",C);const G=_.selectAll("text").attr("x",n/2).attr("y",r/2);return null!==x&&(S.style("font-size","0px"),L.style("font-size",x),G.style("font-size","0px")),{circles:y,textCentres:m,nodes:O,enter:k,update:$,exit:_}}return R.wrap=function(t){return arguments.length?(c=t,R):c},R.useViewBox=function(){return e=!0,R},R.width=function(t){return arguments.length?(n=t,R):n},R.height=function(t){return arguments.length?(r=t,R):r},R.padding=function(t){return arguments.length?(s=t,R):s},R.colours=function(t){return arguments.length?(M=t,R):M},R.fontSize=function(t){return arguments.length?(x=t,R):x},R.duration=function(t){return arguments.length?(i=t,R):i},R.layoutFunction=function(t){return arguments.length?(z=t,R):z},R.normalize=function(t){return arguments.length?(a=t,R):a},R.scaleToFit=function(t){return arguments.length?(l=t,R):l},R.styled=function(t){return arguments.length?(u=t,R):u},R.orientation=function(t){return arguments.length?(o=t,R):o},R.orientationOrder=function(t){return arguments.length?(h=t,R):h},R.lossFunction=function(t){return arguments.length?(I=t,R):I},R},t.bestInitialLayout=p,t.circleArea=r,t.circleCircleIntersection=o,t.circleFromPath=T,t.circleOverlap=i,t.circlePath=j,t.computeTextCentre=A,t.computeTextCentres=P,t.disjointCluster=m,t.distance=s,t.distanceFromIntersectArea=h,t.greedyLayout=d,t.intersectionArea=n,t.intersectionAreaPath=N,t.layout=function(t,e={}){const{lossFunction:n=g,layoutFunction:r=f,normalize:s=!0,orientation:i=Math.PI/2,orientationOrder:o,width:a=600,height:l=350,padding:c=15,scaleToFit:u=!1,symmetricalTextCentre:x=!1}=e;let h=r(t,{lossFunction:n});s&&(h=v(h,i,o));const p=b(h,a,l,c,u),d=P(p,t,x),y=new Map(Object.keys(p).map(t=>[t,{set:t,x:p[t].x,y:p[t].y,radius:p[t].radius}]));return t.map(t=>{const e=t.sets.map(t=>y.get(t)),n=E(e);return{data:t,text:d[t.sets],circles:e,arcs:n,path:C(n)}})},t.lossFunction=g,t.normalizeSolution=v,t.scaleSolution=b,t.sortAreas=function(t,e){const n=F(t.selectAll("svg").datum()),r=new Set;for(const t of e.sets)for(let e in n){const s=n[e];for(let n=0;n<s.length;++n)if(s[n]==t){r.add(e);break}}function s(t){return t.every(t=>!r.has(t))}t.selectAll("g").sort((t,n)=>t.sets.length!=n.sets.length?t.sets.length-n.sets.length:t==e?s(n.sets)?-1:1:n==e?s(t.sets)?1:-1:n.size-t.size)},t.venn=f,t.wrapText=w,Object.defineProperty(t,"__esModule",{value:!0})}); |
{ | ||
"name": "@upsetjs/venn.js", | ||
"description": "Area Proportional Venn and Euler Diagrams", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"publishConfig": { | ||
@@ -53,3 +53,3 @@ "access": "public" | ||
], | ||
"peerDependencies": { | ||
"optionalDependencies": { | ||
"d3-selection": "^1.4.1", | ||
@@ -72,4 +72,2 @@ "d3-transition": "^1.3.2" | ||
"canvas": "^2.6.1", | ||
"d3-selection": "^1.4.1", | ||
"d3-transition": "^1.3.2", | ||
"eslint": "^7.2.0", | ||
@@ -76,0 +74,0 @@ "eslint-config-prettier": "^6.11.0", |
@@ -20,4 +20,20 @@ # venn.js | ||
### Usage | ||
## Usage | ||
There are two modes in which this library can be used. | ||
First, in a managed case by using the `VennDiagram` function that will render the data using D3. | ||
Second, in a manual case as a layout library that is just preparing the data for you. | ||
In the following, these set data are used: | ||
```js | ||
const sets = [ | ||
{ sets: ['A'], size: 12 }, | ||
{ sets: ['B'], size: 12 }, | ||
{ sets: ['A', 'B'], size: 2 }, | ||
]; | ||
``` | ||
### Managed Usage | ||
This library depends on [d3.js](http://d3js.org/) to display the venn | ||
@@ -34,10 +50,4 @@ diagrams. | ||
```javascript | ||
var sets = [ | ||
{ sets: ['A'], size: 12 }, | ||
{ sets: ['B'], size: 12 }, | ||
{ sets: ['A', 'B'], size: 2 }, | ||
]; | ||
var chart = venn.VennDiagram(); | ||
```js | ||
const chart = venn.VennDiagram(); | ||
d3.select('#venn').datum(sets).call(chart); | ||
@@ -53,3 +63,3 @@ ``` | ||
```javascript | ||
```js | ||
var chart = venn.VennDiagram(); | ||
@@ -67,3 +77,3 @@ d3.select('#inverted').datum(sets).call(chart); | ||
```javascript | ||
```js | ||
// draw a diagram with text symmetrically positioned in each circle's centre | ||
@@ -78,3 +88,3 @@ var chart = venn.VennDiagram({ symmetricalTextCentre: true }); | ||
```javascript | ||
```js | ||
// draw the initial diagram | ||
@@ -96,3 +106,3 @@ var chart = venn.VennDiagram(); | ||
```javascript | ||
```js | ||
d3.selectAll('#rings .venn-circle') | ||
@@ -115,3 +125,3 @@ .on('mouseover', function (d, i) { | ||
```javascript | ||
```js | ||
var chart = venn.VennDiagram({ | ||
@@ -129,3 +139,3 @@ colourScheme: ['rgb(235, 237, 238)', '#F26250'], | ||
```javascript | ||
```js | ||
// draw venn diagram | ||
@@ -175,2 +185,55 @@ var div = d3.select('#venn'); | ||
## Manual Usage | ||
Besides the handy `VennDiagram` wrapper, the library can used as a pure layout function using the `layout` method. | ||
One can render the result manually in D3 or even in HTML Canvas. | ||
### Custom D3 Rendering | ||
```js | ||
// compute layout data | ||
const data = venn.layout(sets, { width: 640, height: 640 }); | ||
// custom data binding and rendering | ||
const g = d3 | ||
.select('#venn') | ||
.selectAll('g') | ||
.data(data) | ||
.join((enter) => { | ||
const g = enter.append('g'); | ||
g.append('title'); | ||
g.append('path'); | ||
g.append('text'); | ||
return g; | ||
}); | ||
g.select('title').text((d) => d.data.sets.toString()); | ||
g.select('text') | ||
.text((d) => d.data.sets.toString()) | ||
.attr('x', (d) => d.text.x) | ||
.attr('y', (d) => d.text.y); | ||
g.select('path') | ||
.attr('d', (d) => d.path) | ||
.style('fill', (d, i) => (d.circles.length === 1 ? d3.schemeCategory10[i] : undefined)); | ||
``` | ||
### Canvas Rendering | ||
```js | ||
const data = venn.layout(sets, { width: 640, height: 640 }); | ||
const ctx = document.querySelector('canvas').getContext('2d'); | ||
data.forEach((d, i) => { | ||
ctx.fillStyle = `hsla(${(360 * i) / data.length},80%,50%,0.6)`; | ||
ctx.fill(new Path2D(d.path)); | ||
}); | ||
ctx.font = '16px Helvetica Neue, Helvetica, Arial, sans-serif'; | ||
ctx.textAlign = 'center'; | ||
ctx.textBaseline = 'central'; | ||
ctx.fillStyle = 'white'; | ||
data.forEach((d, i) => { | ||
ctx.fillText(d.data.sets.toString(), d.text.x, d.text.y); | ||
}); | ||
``` | ||
## License | ||
@@ -177,0 +240,0 @@ |
@@ -1,4 +0,1 @@ | ||
import { select } from 'd3-selection'; | ||
import 'd3-transition'; | ||
import { venn, lossFunction, normalizeSolution, scaleSolution } from './layout'; | ||
@@ -135,3 +132,3 @@ import { intersectionArea, distance, getCenter } from './circleintersection'; | ||
svg.selectAll('.venn-area path').each(function (d) { | ||
var path = select(this).attr('d'); | ||
const path = this.getAttribute('d'); | ||
if (d.sets.length == 1 && path) { | ||
@@ -208,6 +205,13 @@ hasPrevious = true; | ||
function asTransition(s) { | ||
if (typeof s.transition === 'function') { | ||
return s.transition('venn').duration(duration); | ||
} | ||
return s; | ||
} | ||
// update existing, using pathTween if necessary | ||
let update = selection; | ||
if (hasPrevious) { | ||
update = selection.transition('venn').duration(duration); | ||
update = asTransition(selection); | ||
update.selectAll('path').attrTween('d', pathTween); | ||
@@ -240,3 +244,3 @@ } else { | ||
// remove old | ||
const exit = nodes.exit().transition('venn').duration(duration).remove(); | ||
const exit = asTransition(nodes.exit()).remove(); | ||
exit.selectAll('path').attrTween('d', pathTween); | ||
@@ -360,5 +364,4 @@ | ||
export function wrapText(circles, labeller) { | ||
return function () { | ||
const text = select(this); | ||
const data = text.datum(); | ||
return function (data) { | ||
const text = this; | ||
const width = circles[data.sets[0]].radius || 50; | ||
@@ -372,7 +375,17 @@ const label = labeller(data) || ''; | ||
let word = words.pop(); | ||
const line = [word]; | ||
let line = [word]; | ||
let lineNumber = 0; | ||
const lineHeight = 1.1; // ems | ||
let tspan = text.text(null).append('tspan').text(word); | ||
text.textContent = null; // clear | ||
const tspans = []; | ||
function append(word) { | ||
const tspan = text.ownerDocument.createElementNS(text.namespaceURI, 'tspan'); | ||
tspan.textContent = word; | ||
tspans.push(tspan); | ||
text.append(tspan); | ||
return tspan; | ||
} | ||
let tspan = append(word); | ||
while (true) { | ||
@@ -385,8 +398,8 @@ word = words.pop(); | ||
const joined = line.join(' '); | ||
tspan.text(joined); | ||
if (joined.length > minChars && tspan.node().getComputedTextLength() > width) { | ||
tspan.textContent = joined; | ||
if (joined.length > minChars && tspan.getComputedTextLength() > width) { | ||
line.pop(); | ||
tspan.text(line.join(' ')); | ||
tspan.textContent = line.join(' '); | ||
line = [word]; | ||
tspan = text.append('tspan').text(word); | ||
tspan = append(word); | ||
lineNumber++; | ||
@@ -397,10 +410,9 @@ } | ||
const initial = 0.35 - (lineNumber * lineHeight) / 2; | ||
const x = text.attr('x'); | ||
const y = text.attr('y'); | ||
text | ||
.selectAll('tspan') | ||
.attr('x', x) | ||
.attr('y', y) | ||
.attr('dy', (_, i) => `${initial + i * lineHeight}em`); | ||
const x = text.getAttribute('x'); | ||
const y = text.getAttribute('y'); | ||
tspans.forEach((t, i) => { | ||
t.setAttribute('x', x); | ||
t.setAttribute('y', y); | ||
t.setAttribute('dy', `${initial + i * lineHeight}em`); | ||
}); | ||
}; | ||
@@ -687,6 +699,6 @@ } | ||
export function computeVennLayout(data, options = {}) { | ||
export function layout(data, options = {}) { | ||
const { | ||
lossFunction = lossFunction, | ||
layoutFunction = layoutFunction, | ||
lossFunction: loss = lossFunction, | ||
layoutFunction: layout = venn, | ||
normalize = true, | ||
@@ -702,3 +714,3 @@ orientation = Math.PI / 2, | ||
let solution = layoutFunction(data, { lossFunction }); | ||
let solution = layout(data, { lossFunction: loss }); | ||
@@ -720,3 +732,2 @@ if (normalize) { | ||
radius: circles[set].radius, | ||
text: textCentres[set], | ||
}, | ||
@@ -726,27 +737,2 @@ ]) | ||
function intersectionAreaPath(circles) { | ||
if (circles.length === 0) { | ||
return []; | ||
} | ||
const stats = {}; | ||
intersectionArea(circles, stats); | ||
const arcs = stats.arcs; | ||
if (arcs.length === 0) { | ||
return []; | ||
} | ||
if (arcs.length == 1) { | ||
const circle = arcs[0].circle; | ||
return circlePath(circle.x, circle.y, circle.radius); | ||
} | ||
// draw path around arcs | ||
const ret = ['\nM', arcs[0].p2.x, arcs[0].p2.y]; | ||
for (const arc of arcs) { | ||
const r = arc.circle.radius; | ||
const wide = arc.width > r; | ||
ret.push('\nA', r, r, 0, wide ? 1 : 0, 1, arc.p1.x, arc.p1.y); | ||
} | ||
return ret.join(' '); | ||
} | ||
return data.map((area) => { | ||
@@ -756,3 +742,4 @@ const circles = area.sets.map((s) => circleLookup.get(s)); | ||
return { | ||
data, | ||
data: area, | ||
text: textCentres[area.sets], | ||
circles, | ||
@@ -759,0 +746,0 @@ arcs, |
@@ -250,8 +250,12 @@ import { Selection } from 'd3-selection'; | ||
export interface IVennLayout { | ||
data: ISetOverlap; | ||
circles: readonly (ICircle & { set: string; text: IPoint })[]; | ||
export interface IVennLayout<T> { | ||
data: T; | ||
text: IPoint; | ||
circles: readonly (ICircle & { set: string })[]; | ||
arcs: readonly { circle: ICircle; width: number; p1: IPoint; p2: IPoint }[]; | ||
path: string; | ||
} | ||
export function computeVennLayout(data: readonly ISetOverlap[], options?: IComputeVennLayoutOptions): IVennLayout[]; | ||
export function layout<T extends ISetOverlap>( | ||
data: readonly T[], | ||
options?: IComputeVennLayoutOptions | ||
): IVennLayout<T>[]; |
@@ -21,3 +21,3 @@ export { intersectionArea, circleCircleIntersection, circleOverlap, circleArea, distance } from './circleintersection'; | ||
intersectionAreaPath, | ||
computeVennLayout, | ||
layout, | ||
} from './diagram'; |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
228526
20
5561
0
259