完成世界书、骰子、apiconfig页面处理
This commit is contained in:
267
frontend/node_modules/@upsetjs/venn.js/README.md
generated
vendored
Normal file
267
frontend/node_modules/@upsetjs/venn.js/README.md
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
# venn.js
|
||||
|
||||
[![License: MIT][mit-image]][mit-url] [![NPM Package][npm-image]][npm-url] [![Github Actions][github-actions-image]][github-actions-url]
|
||||
|
||||
This is a maintained fork of [https://github.com/benfred/venn.js](https://github.com/benfred/venn.js).
|
||||
|
||||
A javascript library for laying out area proportional venn and euler diagrams.
|
||||
|
||||
Details of how this library works can be found on the [blog
|
||||
post](https://www.benfrederickson.com/venn-diagrams-with-d3.js/)
|
||||
the original author wrote about this. A follow up post [discusses testing strategy and
|
||||
algorithmic improvements](https://www.benfrederickson.com/better-venn-diagrams/).
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install --save @upsetjs/venn.js
|
||||
```
|
||||
|
||||
## 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](https://d3js.org/) to display the venn
|
||||
diagrams.
|
||||
|
||||
##### Simple layout
|
||||
|
||||
To lay out a simple diagram, just define the sets and their sizes along with the sizes
|
||||
of all the set intersections.
|
||||
|
||||
The VennDiagram object will calculate a layout that is proportional to the
|
||||
input sizes, and display it in the appropriate selection when called:
|
||||
|
||||
```js
|
||||
const chart = venn.VennDiagram();
|
||||
d3.select('#venn').datum(sets).call(chart);
|
||||
```
|
||||
|
||||
[View this example](https://upset.js.org/venn.js/examples/simple.html)
|
||||
|
||||
[![Open in CodePen][codepen]](https://codepen.io/sgratzl/pen/RwrKPEe)
|
||||
|
||||
##### Changing the Style
|
||||
|
||||
The style of the Venn Diagram can be customized by using D3 after the diagram
|
||||
has been drawn. For instance to draw a Venn Diagram with white text and a darker fill:
|
||||
|
||||
```js
|
||||
const chart = venn.VennDiagram();
|
||||
d3.select('#inverted').datum(sets).call(chart);
|
||||
|
||||
d3.selectAll('#inverted .venn-circle path').style('fill-opacity', 0.8);
|
||||
|
||||
d3.selectAll('#inverted text').style('fill', 'white');
|
||||
```
|
||||
|
||||
[View this example, along with other possible styles](https://upset.js.org/venn.js/examples/styled.html)
|
||||
|
||||
The position of text within each circle of the diagram may also be modified via the `symmetricalTextCentre` property (defaults to `false`):
|
||||
|
||||
```js
|
||||
// draw a diagram with text symmetrically positioned in each circle's centre
|
||||
const chart = venn.VennDiagram({ symmetricalTextCentre: true });
|
||||
```
|
||||
|
||||
##### Dynamic layout
|
||||
|
||||
To have a layout that reacts to a change in input, all that you need to do is
|
||||
update the dataset and call the chart again:
|
||||
|
||||
```js
|
||||
// draw the initial diagram
|
||||
const chart = venn.VennDiagram();
|
||||
d3.select('#venn').datum(getSetIntersections()).call(chart);
|
||||
|
||||
// redraw the diagram on any change in input
|
||||
d3.selectAll('input').on('change', function () {
|
||||
d3.select('#venn').datum(getSetIntersections()).call(chart);
|
||||
});
|
||||
```
|
||||
|
||||
[View this example](https://upset.js.org/venn.js/examples/dynamic.html)
|
||||
|
||||
##### Making the diagram interactive
|
||||
|
||||
Making the diagram interactive is basically the same idea as changing the style: just add event listeners to the elements in the venn diagram. To change the text size and circle colours on mouseenter:
|
||||
|
||||
```js
|
||||
d3.selectAll('#rings .venn-circle')
|
||||
.on('mouseenter', function () {
|
||||
const node = d3.select(this).transition();
|
||||
node.select('path').style('fill-opacity', 0.2);
|
||||
node.select('text').style('font-weight', '100').style('font-size', '36px');
|
||||
})
|
||||
.on('mouseleave', function () {
|
||||
const node = d3.select(this).transition();
|
||||
node.select('path').style('fill-opacity', 0);
|
||||
node.select('text').style('font-weight', '100').style('font-size', '24px');
|
||||
});
|
||||
```
|
||||
|
||||
[View this example](https://upset.js.org/venn.js/examples/interactive.html)
|
||||
|
||||
The colour scheme for the diagram's circles may also be modified via the `colorScheme` option, and the text within each circle can have its fill modified via the `textFill` option:
|
||||
|
||||
```js
|
||||
const chart = venn.VennDiagram({
|
||||
colorScheme: ['rgb(235, 237, 238)', '#F26250'],
|
||||
textFill: '#FFF',
|
||||
});
|
||||
```
|
||||
|
||||
##### Adding tooltips
|
||||
|
||||
Another common case is adding a tooltip when hovering over the elements in the diagram. The only
|
||||
tricky thing here is maintaining the correct Z-order so that the smallest intersection areas
|
||||
are on top, while still making the area that is being hovered over appear on top of the others:
|
||||
|
||||
```js
|
||||
// draw venn diagram
|
||||
const div = d3.select('#venn');
|
||||
div.datum(sets).call(venn.VennDiagram());
|
||||
|
||||
// add a tooltip
|
||||
const tooltip = d3.select('body').append('div').attr('class', 'venntooltip');
|
||||
|
||||
// add listeners to all the groups to display tooltip on mouseenter
|
||||
div
|
||||
.selectAll('g')
|
||||
.on('mouseenter', function (d) {
|
||||
// sort all the areas relative to the current item
|
||||
venn.sortAreas(div, d);
|
||||
|
||||
// Display a tooltip with the current size
|
||||
tooltip.transition().duration(400).style('opacity', 0.9);
|
||||
tooltip.text(d.size + ' users');
|
||||
|
||||
// highlight the current path
|
||||
const selection = d3.select(this).transition('tooltip').duration(400);
|
||||
selection
|
||||
.select('path')
|
||||
.style('stroke-width', 3)
|
||||
.style('fill-opacity', d.sets.length == 1 ? 0.4 : 0.1)
|
||||
.style('stroke-opacity', 1);
|
||||
})
|
||||
|
||||
.on('mousemove', function () {
|
||||
tooltip.style('left', d3.event.pageX + 'px').style('top', d3.event.pageY - 28 + 'px');
|
||||
})
|
||||
|
||||
.on('mouseleave', function (d) {
|
||||
tooltip.transition().duration(400).style('opacity', 0);
|
||||
const selection = d3.select(this).transition('tooltip').duration(400);
|
||||
selection
|
||||
.select('path')
|
||||
.style('stroke-width', 0)
|
||||
.style('fill-opacity', d.sets.length == 1 ? 0.25 : 0.0)
|
||||
.style('stroke-opacity', 0);
|
||||
});
|
||||
```
|
||||
|
||||
[View this example](https://upset.js.org/venn.js/examples/intersection_tooltip.html)
|
||||
|
||||
## 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.
|
||||
|
||||
The signature of the function can be found as part of the TypeScript typings at [index.ds.ts](https://github.com/upsetjs/venn.js/blob/master/src/index.d.ts)
|
||||
|
||||
### Custom D3 Rendering
|
||||
|
||||
```js
|
||||
// compute layout data
|
||||
const data = venn.layout(sets);
|
||||
// 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));
|
||||
```
|
||||
|
||||
[![Open in CodePen][codepen]](https://codepen.io/sgratzl/pen/xxZgGeP)
|
||||
|
||||
### Canvas Rendering
|
||||
|
||||
```js
|
||||
const data = venn.layout(sets, { width: 600, height: 350 });
|
||||
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);
|
||||
});
|
||||
```
|
||||
|
||||
[![Open in CodePen][codepen]](https://codepen.io/sgratzl/pen/NWxdqZW)
|
||||
|
||||
## License
|
||||
|
||||
Released under the MIT License.
|
||||
|
||||
## Development Environment
|
||||
|
||||
```sh
|
||||
npm i -g yarn
|
||||
yarn install
|
||||
yarn sdks vscode
|
||||
```
|
||||
|
||||
### Common commands
|
||||
|
||||
```sh
|
||||
yarn test
|
||||
yarn lint
|
||||
yarn format
|
||||
yarn build
|
||||
yarn release
|
||||
yarn release:pre
|
||||
```
|
||||
|
||||
[mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg
|
||||
[mit-url]: https://opensource.org/licenses/MIT
|
||||
[npm-image]: https://badge.fury.io/js/%40upsetjs%2Fvenn.js.svg
|
||||
[npm-url]: https://npmjs.org/package/@upsetjs/venn.js
|
||||
[github-actions-image]: https://github.com/upsetjs/venn.js/workflows/ci/badge.svg
|
||||
[github-actions-url]: https://github.com/upsetjs/venn.js/actions
|
||||
[codepen]: https://img.shields.io/badge/CodePen-open-blue?logo=codepen
|
||||
105
frontend/node_modules/@upsetjs/venn.js/package.json
generated
vendored
Normal file
105
frontend/node_modules/@upsetjs/venn.js/package.json
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"name": "@upsetjs/venn.js",
|
||||
"description": "Area Proportional Venn and Euler Diagrams",
|
||||
"version": "2.0.0",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": {
|
||||
"name": "Ben Frederickson",
|
||||
"email": "ben@benfrederickson.com",
|
||||
"url": "https://www.benfrederickson.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Samuel Gratzl",
|
||||
"email": "samu@sgratzl.com",
|
||||
"url": "https://wwww.sgratzl.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/upsetjs/venn.js",
|
||||
"bugs": {
|
||||
"url": "https://github.com/upsetjs/venn.js/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"Venn",
|
||||
"Euler"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/upsetjs/venn.js.git"
|
||||
},
|
||||
"directories": {
|
||||
"example": "examples",
|
||||
"test": "tests"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "build/venn.esm.js",
|
||||
"module": "build/venn.esm.js",
|
||||
"require": "build/venn.js",
|
||||
"unpkg": "build/venn.min.js",
|
||||
"jsdelivr": "build/venn.min.js",
|
||||
"types": "src/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./build/venn.esm.js",
|
||||
"require": "./build/index.js",
|
||||
"scripts": "./build/venn.min.js",
|
||||
"types": "./src/index.d.ts"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"build",
|
||||
"src/**/*.js",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"browserslist": [
|
||||
"Firefox ESR",
|
||||
"last 2 Chrome versions",
|
||||
"last 2 Firefox versions"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-transition": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/plugin-transform-runtime": "^7.25.9",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@eslint/js": "^9.15.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^28.0.1",
|
||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||
"@yarnpkg/sdks": "^3.2.0",
|
||||
"canvas": "^2.11.2",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-transition": "^3.0.1",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"fmin": "patch:fmin@npm%3A0.0.4#~/.yarn/patches/fmin-npm-0.0.4-e439f499bd.patch",
|
||||
"globals": "^15.12.0",
|
||||
"jest-image-snapshot": "^6.4.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"prettier": "^3.3.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup": "^4.27.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"vite": "^5.4.11",
|
||||
"vitest": "^2.1.5"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf --glob build *.tgz",
|
||||
"watch": "rollup -c -w",
|
||||
"lint": "eslint src",
|
||||
"test": "vitest --passWithNoTests",
|
||||
"test:watch": "vitest --watch",
|
||||
"posttest": "npm run lint",
|
||||
"prebuild": "npm run clean && npm test",
|
||||
"build": "rollup -c",
|
||||
"format": "prettier --write examples \"*.{md,json,js,yml}\" \"{.github,src,examples}/**\""
|
||||
},
|
||||
"packageManager": "yarn@4.5.1"
|
||||
}
|
||||
119
frontend/node_modules/@upsetjs/venn.js/src/layout.spec.js
generated
vendored
Normal file
119
frontend/node_modules/@upsetjs/venn.js/src/layout.spec.js
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
import { disjointCluster, normalizeSolution, greedyLayout, lossFunction, distanceFromIntersectArea } from './layout';
|
||||
import { distance, circleOverlap } from './circleintersection';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
|
||||
describe('greedyLayout', () => {
|
||||
test('0', () => {
|
||||
const areas = [
|
||||
{ sets: [0], size: 0.7746543297103429 },
|
||||
{ sets: [1], size: 0.1311252856844238 },
|
||||
{ sets: [2], size: 0.2659942131443344 },
|
||||
{ sets: [3], size: 0.44600866168641723 },
|
||||
{ sets: [0, 1], size: 0.02051532092950205 },
|
||||
{ sets: [0, 2], size: 0 },
|
||||
{ sets: [0, 3], size: 0 },
|
||||
{ sets: [1, 2], size: 0 },
|
||||
{ sets: [1, 3], size: 0.07597023820511245 },
|
||||
{ sets: [2, 3], size: 0 },
|
||||
];
|
||||
const circles = greedyLayout(areas);
|
||||
const loss = lossFunction(circles, areas);
|
||||
expect(loss).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('1', () => {
|
||||
const areas = [
|
||||
{ sets: [0], size: 0.5299368855059736 },
|
||||
{ sets: [1], size: 0.03364187025606481 },
|
||||
{ sets: [2], size: 0.3121450394871512 },
|
||||
{ sets: [3], size: 0.0514397361783036 },
|
||||
{ sets: [0, 1], size: 0.013912447645582351 },
|
||||
{ sets: [0, 2], size: 0.005903647141469598 },
|
||||
{ sets: [0, 3], size: 0.0514397361783036 },
|
||||
{ sets: [1, 2], size: 0.012138157839477597 },
|
||||
{ sets: [1, 3], size: 0.008010688232481479 },
|
||||
{ sets: [2, 3], size: 0 },
|
||||
];
|
||||
|
||||
const circles = greedyLayout(areas);
|
||||
const loss = lossFunction(circles, areas);
|
||||
expect(loss).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('3', () => {
|
||||
// one small circle completely overlapped in the intersection
|
||||
// area of two larger circles
|
||||
const areas = [
|
||||
{ sets: [0], size: 1.7288584050841396 },
|
||||
{ sets: [1], size: 0.040875831658950056 },
|
||||
{ sets: [2], size: 2.587146019782323 },
|
||||
{ sets: [0, 1], size: 0.040875831658950056 },
|
||||
{ sets: [0, 2], size: 0.5114617575187569 },
|
||||
{ sets: [1, 2], size: 0.040875831658950056 },
|
||||
];
|
||||
|
||||
const circles = greedyLayout(areas);
|
||||
const loss = lossFunction(circles, areas);
|
||||
expect(loss).toBeCloseTo(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('distanceFromIntersectArea', () => {
|
||||
function testDistanceFromIntersectArea(r1, r2, overlap) {
|
||||
const distance = distanceFromIntersectArea(r1, r2, overlap);
|
||||
expect(circleOverlap(r1, r2, distance)).toBeCloseTo(overlap);
|
||||
}
|
||||
|
||||
testDistanceFromIntersectArea(1.9544100476116797, 2.256758334191025, 11);
|
||||
|
||||
testDistanceFromIntersectArea(111.06512962798197, 113.32348546565727, 1218);
|
||||
|
||||
testDistanceFromIntersectArea(44.456564007075, 149.4335753619362, 2799);
|
||||
|
||||
testDistanceFromIntersectArea(592.89, 134.75, 56995);
|
||||
|
||||
testDistanceFromIntersectArea(139.50778247443944, 32.892784970851956, 3399);
|
||||
|
||||
testDistanceFromIntersectArea(4.886025119029199, 5.077706251929807, 75);
|
||||
});
|
||||
|
||||
test('normalizeSolution', () => {
|
||||
// test two circles that are far apart
|
||||
const solution = [
|
||||
{ x: 0, y: 0, radius: 0.5 },
|
||||
{ x: 1e10, y: 0, radius: 1.5 },
|
||||
];
|
||||
|
||||
// should be placed close together
|
||||
const normalized = normalizeSolution(solution);
|
||||
// distance should be 2, but we space things out
|
||||
expect(distance(normalized[0], normalized[1])).toBeLessThan(2.1);
|
||||
});
|
||||
|
||||
test('disjointClusters', () => {
|
||||
const input = [
|
||||
{
|
||||
x: 0.8047033110633492,
|
||||
y: 0.9396705999970436,
|
||||
radius: 0.47156485118903224,
|
||||
},
|
||||
{
|
||||
x: 0.7961132447235286,
|
||||
y: 0.014027722179889679,
|
||||
radius: 0.14554832570720466,
|
||||
},
|
||||
{
|
||||
x: 0.28841276094317436,
|
||||
y: 0.98081015329808,
|
||||
radius: 0.9851036085514352,
|
||||
},
|
||||
{
|
||||
x: 0.7689983483869582,
|
||||
y: 0.2899463507346809,
|
||||
radius: 0.7210563338827342,
|
||||
},
|
||||
];
|
||||
|
||||
const clusters = disjointCluster(input);
|
||||
expect(clusters).toHaveLength(1);
|
||||
});
|
||||
Reference in New Issue
Block a user