From 9d09f2bb31b7d336f1d615bc9fde5226c213e88b Mon Sep 17 00:00:00 2001 From: Bridge Tools Date: Mon, 8 Mar 2021 13:48:39 +0200 Subject: [PATCH] Embed rc-spider lib --- .eslintrc | 2 +- .prettierignore | 3 +- package.json | 1 - .../PatternJourney/PatternJourney.js | 2 +- src/libs/rc-spider/.editorconfig | 9 + src/libs/rc-spider/.eslintignore | 1 + src/libs/rc-spider/.gitignore | 24 ++ src/libs/rc-spider/.travis.yml | 38 ++ src/libs/rc-spider/HISTORY.md | 21 + src/libs/rc-spider/README.md | 100 +++++ src/libs/rc-spider/examples/cluster.html | 1 + src/libs/rc-spider/examples/cluster.js | 53 +++ src/libs/rc-spider/examples/flare.json | 381 ++++++++++++++++++ src/libs/rc-spider/examples/mindNode.html | 1 + src/libs/rc-spider/examples/mindNode.js | 6 + .../rc-spider/examples/mindNode/index.jsx | 117 ++++++ src/libs/rc-spider/examples/network.html | 1 + src/libs/rc-spider/examples/network.js | 38 ++ src/libs/rc-spider/examples/network.json | 36 ++ .../rc-spider/examples/pattern-journey.html | 1 + .../rc-spider/examples/pattern-journey.js | 56 +++ .../rc-spider/examples/pattern-journey.json | 234 +++++++++++ src/libs/rc-spider/examples/simple.html | 1 + src/libs/rc-spider/examples/simple.js | 31 ++ src/libs/rc-spider/examples/tree.html | 1 + src/libs/rc-spider/examples/tree.js | 31 ++ src/libs/rc-spider/examples/tree.json | 30 ++ src/libs/rc-spider/index.js | 3 + src/libs/rc-spider/lib/Spider.js | 334 +++++++++++++++ src/libs/rc-spider/lib/base/Node.js | 148 +++++++ src/libs/rc-spider/lib/base/SpiderBase.js | 113 ++++++ src/libs/rc-spider/lib/base/Util.js | 132 ++++++ src/libs/rc-spider/lib/base/global.js | 21 + src/libs/rc-spider/lib/color/index.js | 28 ++ src/libs/rc-spider/lib/dataLoader/index.js | 135 +++++++ src/libs/rc-spider/lib/index.js | 15 + src/libs/rc-spider/lib/layout/base.js | 28 ++ src/libs/rc-spider/lib/layout/cluster.js | 98 +++++ src/libs/rc-spider/lib/layout/index.js | 16 + src/libs/rc-spider/lib/layout/tree.js | 206 ++++++++++ src/libs/rc-spider/lib/shapes/Circle.js | 56 +++ src/libs/rc-spider/lib/shapes/Link.js | 107 +++++ src/libs/rc-spider/lib/shapes/Node.js | 94 +++++ src/libs/rc-spider/lib/shapes/Rect.js | 82 ++++ src/libs/rc-spider/lib/shapes/Shape.js | 42 ++ src/libs/rc-spider/lib/shapes/Text.js | 72 ++++ src/libs/rc-spider/lib/shapes/index.js | 36 ++ src/libs/rc-spider/lib/theme/default.js | 1 + src/libs/rc-spider/package.json | 61 +++ src/libs/rc-spider/src/Spider.jsx | 249 ++++++++++++ src/libs/rc-spider/src/base/Node.js | 123 ++++++ src/libs/rc-spider/src/base/SpiderBase.jsx | 70 ++++ src/libs/rc-spider/src/base/Util.js | 129 ++++++ src/libs/rc-spider/src/base/global.js | 15 + src/libs/rc-spider/src/color/index.js | 9 + src/libs/rc-spider/src/dataLoader/index.js | 116 ++++++ src/libs/rc-spider/src/index.js | 3 + src/libs/rc-spider/src/layout/base.js | 15 + src/libs/rc-spider/src/layout/cluster.js | 61 +++ src/libs/rc-spider/src/layout/index.js | 8 + src/libs/rc-spider/src/layout/tree.js | 157 ++++++++ src/libs/rc-spider/src/shapes/Circle.jsx | 15 + src/libs/rc-spider/src/shapes/Link.jsx | 58 +++ src/libs/rc-spider/src/shapes/Node.jsx | 50 +++ src/libs/rc-spider/src/shapes/Rect.jsx | 33 ++ src/libs/rc-spider/src/shapes/Shape.jsx | 20 + src/libs/rc-spider/src/shapes/Text.jsx | 26 ++ src/libs/rc-spider/src/shapes/index.jsx | 13 + src/libs/rc-spider/src/theme/default.js | 0 src/libs/rc-spider/tests/index.js | 6 + 70 files changed, 4220 insertions(+), 4 deletions(-) create mode 100644 src/libs/rc-spider/.editorconfig create mode 100644 src/libs/rc-spider/.eslintignore create mode 100644 src/libs/rc-spider/.gitignore create mode 100644 src/libs/rc-spider/.travis.yml create mode 100644 src/libs/rc-spider/HISTORY.md create mode 100644 src/libs/rc-spider/README.md create mode 100644 src/libs/rc-spider/examples/cluster.html create mode 100644 src/libs/rc-spider/examples/cluster.js create mode 100644 src/libs/rc-spider/examples/flare.json create mode 100644 src/libs/rc-spider/examples/mindNode.html create mode 100644 src/libs/rc-spider/examples/mindNode.js create mode 100644 src/libs/rc-spider/examples/mindNode/index.jsx create mode 100644 src/libs/rc-spider/examples/network.html create mode 100644 src/libs/rc-spider/examples/network.js create mode 100644 src/libs/rc-spider/examples/network.json create mode 100644 src/libs/rc-spider/examples/pattern-journey.html create mode 100644 src/libs/rc-spider/examples/pattern-journey.js create mode 100644 src/libs/rc-spider/examples/pattern-journey.json create mode 100644 src/libs/rc-spider/examples/simple.html create mode 100644 src/libs/rc-spider/examples/simple.js create mode 100644 src/libs/rc-spider/examples/tree.html create mode 100644 src/libs/rc-spider/examples/tree.js create mode 100644 src/libs/rc-spider/examples/tree.json create mode 100644 src/libs/rc-spider/index.js create mode 100644 src/libs/rc-spider/lib/Spider.js create mode 100644 src/libs/rc-spider/lib/base/Node.js create mode 100644 src/libs/rc-spider/lib/base/SpiderBase.js create mode 100644 src/libs/rc-spider/lib/base/Util.js create mode 100644 src/libs/rc-spider/lib/base/global.js create mode 100644 src/libs/rc-spider/lib/color/index.js create mode 100644 src/libs/rc-spider/lib/dataLoader/index.js create mode 100644 src/libs/rc-spider/lib/index.js create mode 100644 src/libs/rc-spider/lib/layout/base.js create mode 100644 src/libs/rc-spider/lib/layout/cluster.js create mode 100644 src/libs/rc-spider/lib/layout/index.js create mode 100644 src/libs/rc-spider/lib/layout/tree.js create mode 100644 src/libs/rc-spider/lib/shapes/Circle.js create mode 100644 src/libs/rc-spider/lib/shapes/Link.js create mode 100644 src/libs/rc-spider/lib/shapes/Node.js create mode 100644 src/libs/rc-spider/lib/shapes/Rect.js create mode 100755 src/libs/rc-spider/lib/shapes/Shape.js create mode 100644 src/libs/rc-spider/lib/shapes/Text.js create mode 100755 src/libs/rc-spider/lib/shapes/index.js create mode 100644 src/libs/rc-spider/lib/theme/default.js create mode 100644 src/libs/rc-spider/package.json create mode 100644 src/libs/rc-spider/src/Spider.jsx create mode 100644 src/libs/rc-spider/src/base/Node.js create mode 100644 src/libs/rc-spider/src/base/SpiderBase.jsx create mode 100644 src/libs/rc-spider/src/base/Util.js create mode 100644 src/libs/rc-spider/src/base/global.js create mode 100644 src/libs/rc-spider/src/color/index.js create mode 100644 src/libs/rc-spider/src/dataLoader/index.js create mode 100644 src/libs/rc-spider/src/index.js create mode 100644 src/libs/rc-spider/src/layout/base.js create mode 100644 src/libs/rc-spider/src/layout/cluster.js create mode 100644 src/libs/rc-spider/src/layout/index.js create mode 100644 src/libs/rc-spider/src/layout/tree.js create mode 100644 src/libs/rc-spider/src/shapes/Circle.jsx create mode 100644 src/libs/rc-spider/src/shapes/Link.jsx create mode 100644 src/libs/rc-spider/src/shapes/Node.jsx create mode 100644 src/libs/rc-spider/src/shapes/Rect.jsx create mode 100755 src/libs/rc-spider/src/shapes/Shape.jsx create mode 100644 src/libs/rc-spider/src/shapes/Text.jsx create mode 100755 src/libs/rc-spider/src/shapes/index.jsx create mode 100644 src/libs/rc-spider/src/theme/default.js create mode 100644 src/libs/rc-spider/tests/index.js diff --git a/.eslintrc b/.eslintrc index d60f186c7..aa03827d4 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,7 +6,7 @@ "es6": true }, "parser": "babel-eslint", - "ignorePatterns": ["public", ".cache", "node_modules"], + "ignorePatterns": ["public", ".cache", "node_modules", "src/libs"], "rules": { "strict": 0, "no-console": 1, diff --git a/.prettierignore b/.prettierignore index dbffd4de2..a3b1ca180 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ public/ .cache/ -node_modules/ \ No newline at end of file +node_modules/ +src/libs/ \ No newline at end of file diff --git a/package.json b/package.json index fa19e40e5..6dae9e4f6 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "postcss-text-remove-gap": "^1.1.1", "prismjs": "^1.20.0", "prop-types": "^15.7.2", - "rc-spider": "git+ssh://git@github.com/intergalactico/spider.git#master", "react": "^16.8.6", "react-calendly": "^1.3.0", "react-children-utilities": "^2.1.6", diff --git a/src/components/PatternJourney/PatternJourney.js b/src/components/PatternJourney/PatternJourney.js index e9eb7df19..79dcc0b6c 100644 --- a/src/components/PatternJourney/PatternJourney.js +++ b/src/components/PatternJourney/PatternJourney.js @@ -2,9 +2,9 @@ import React from "react"; import styled from "styled-components"; +import Spider from "../../libs/rc-spider"; import theme from "../theme"; import data from "./PatternJourney.data.js"; -import Spider from "rc-spider"; import FaClose from "react-icons/lib/fa/close"; import breakpoint from "styled-components-breakpoint"; diff --git a/src/libs/rc-spider/.editorconfig b/src/libs/rc-spider/.editorconfig new file mode 100644 index 000000000..54ad30d31 --- /dev/null +++ b/src/libs/rc-spider/.editorconfig @@ -0,0 +1,9 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*.{js,jsx,css}] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/src/libs/rc-spider/.eslintignore b/src/libs/rc-spider/.eslintignore new file mode 100644 index 000000000..56bef8cb3 --- /dev/null +++ b/src/libs/rc-spider/.eslintignore @@ -0,0 +1 @@ +examples/ \ No newline at end of file diff --git a/src/libs/rc-spider/.gitignore b/src/libs/rc-spider/.gitignore new file mode 100644 index 000000000..2e575e566 --- /dev/null +++ b/src/libs/rc-spider/.gitignore @@ -0,0 +1,24 @@ +*.iml +*.log +.idea +.ipr +.iws +*~ +~* +*.diff +*.patch +*.bak +.DS_Store +Thumbs.db +.project +.*proj +.svn +*.swp +*.swo +*.pyc +*.pyo +node_modules +.cache +*.css +build +coverage diff --git a/src/libs/rc-spider/.travis.yml b/src/libs/rc-spider/.travis.yml new file mode 100644 index 000000000..3a0fc79ba --- /dev/null +++ b/src/libs/rc-spider/.travis.yml @@ -0,0 +1,38 @@ +language: node_js + +sudo: false + +notifications: + email: + - surgesoft@gmail.com + +node_js: +- 5.4.1 + +before_install: +- | + if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)|(^(docs|examples))/' + then + echo "Only docs were updated, stopping build process." + exit + fi + npm install npm@3.x -g + phantomjs --version +script: +- | + if [ "$TEST_TYPE" = test ]; then + npm test + else + npm run $TEST_TYPE + fi +env: + matrix: + - TEST_TYPE=lint + - TEST_TYPE=test + - TEST_TYPE=coverage + - TEST_TYPE=saucelabs + + +matrix: + allow_failures: + - env: "TEST_TYPE=saucelabs" \ No newline at end of file diff --git a/src/libs/rc-spider/HISTORY.md b/src/libs/rc-spider/HISTORY.md new file mode 100644 index 000000000..c2c45e532 --- /dev/null +++ b/src/libs/rc-spider/HISTORY.md @@ -0,0 +1,21 @@ +## v0.0.8 + * `network` layout +## v0.0.7 + * `mindNode` example add + +### v0.0.5 +* `Text` element now supported setting `alignment` props (left|center|right) to set text alignment. + +* `transform` and `projection` prop on `` component will effect whole graph but node only. + +* to set `transform` or `projection` prop of node, set `transform` or `projection` prop of `` component directly, + + or set `NodeTransform` or `NodeProjection` attribute of `` + + +### v0.0.4 +using tidier drawing algorithm to draw tree + +### v0.0.3 + +tree-layout supported. \ No newline at end of file diff --git a/src/libs/rc-spider/README.md b/src/libs/rc-spider/README.md new file mode 100644 index 000000000..853b17268 --- /dev/null +++ b/src/libs/rc-spider/README.md @@ -0,0 +1,100 @@ +# rc-spider +--- + +React Spider Component + +[![NPM version][npm-image]][npm-url] +[![build status][travis-image]][travis-url] +[![Test coverage][coveralls-image]][coveralls-url] +[![gemnasium deps][gemnasium-image]][gemnasium-url] +[![npm download][download-image]][download-url] + +[npm-image]: http://img.shields.io/npm/v/rc-spider.svg?style=flat-square +[npm-url]: http://npmjs.org/package/rc-spider +[travis-image]: https://img.shields.io/travis/react-component/spider.svg?style=flat-square +[travis-url]: https://travis-ci.org/react-component/spider +[coveralls-image]: https://img.shields.io/coveralls/react-component/spider.svg?style=flat-square +[coveralls-url]: https://coveralls.io/r/react-component/spider?branch=master +[gemnasium-image]: http://img.shields.io/gemnasium/react-component/spider.svg?style=flat-square +[gemnasium-url]: https://gemnasium.com/react-component/spider +[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square +[node-url]: http://nodejs.org/download/ +[download-image]: https://img.shields.io/npm/dm/rc-spider.svg?style=flat-square +[download-url]: https://npmjs.org/package/rc-spider + +## Screenshots + + + + +## Development + +``` +npm install +npm start +``` + +## Example + +http://localhost:8000/examples/ + + +online example: http://react-component.github.io/spider/ + + +## install + + +[![rc-spider](https://nodei.co/npm/rc-spider.png)](https://npmjs.org/package/rc-spider) + + +## Usage + +```js +var Spider = require('rc-spider'); +var React = require('react'); +React.render(, container); +``` + +## API + +### props + + + + + + + + + + + + + + + + + + +
nametypedefaultdescription
classNameStringadditional css class of root dom node
+ + +## Test Case + +``` +npm test +npm run chrome-test +``` + +## Coverage + +``` +npm run coverage +``` + +open coverage/ dir + +## License + +rc-spider is released under the MIT license. diff --git a/src/libs/rc-spider/examples/cluster.html b/src/libs/rc-spider/examples/cluster.html new file mode 100644 index 000000000..b3a425249 --- /dev/null +++ b/src/libs/rc-spider/examples/cluster.html @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/src/libs/rc-spider/examples/cluster.js b/src/libs/rc-spider/examples/cluster.js new file mode 100644 index 000000000..bfa39f19a --- /dev/null +++ b/src/libs/rc-spider/examples/cluster.js @@ -0,0 +1,53 @@ +import 'normalize.css'; +import Spider from 'rc-spider'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const width = 1280; +const height = 800; +const rx = width / 2; +const ry = height / 2; + +const { Node, Circle, Text, Link } = Spider.Shape; + +function onClick(d, e) { + console.log('>> onClick', this); +} + +function nodeCreator(data) { + return ( + + + {data.name} + + ); +} + +function projection (d) { + return [d.y, d.x / 180 * Math.PI] +} +function radial (data) { + var d = projection.apply(this, arguments), r = d[0], a = d[1] - Math.PI / 2; + return [ r * Math.cos(a), r * Math.sin(a) ]; +} + +function linkCreator (data) { + return ; +} + +const data = new Request('./flare.json'); +fetch(data).then(response => response.json()) + .then(response => { + const tree = response; + const cluster = Spider.layout.cluster().size([360, ry - 120]); + const data = cluster.data(tree); + ReactDOM.render( new Spider.Transform().rotate(d.x - 90).translate(d.y)} + nodeCreator={nodeCreator} + linkCreator={linkCreator} + />, document.getElementById('__react-content')); + }); + diff --git a/src/libs/rc-spider/examples/flare.json b/src/libs/rc-spider/examples/flare.json new file mode 100644 index 000000000..36025f44c --- /dev/null +++ b/src/libs/rc-spider/examples/flare.json @@ -0,0 +1,381 @@ + +{ + "name": "flare", + "children": [ + { + "name": "analytics", + "children": [ + { + "name": "cluster", + "children": [ + {"name": "AgglomerativeCluster", "size": 3938}, + {"name": "CommunityStructure", "size": 3812}, + {"name": "HierarchicalCluster", "size": 6714}, + {"name": "MergeEdge", "size": 743} + ] + }, + { + "name": "graph", + "children": [ + {"name": "BetweennessCentrality", "size": 3534}, + {"name": "LinkDistance", "size": 5731}, + {"name": "MaxFlowMinCut", "size": 7840}, + {"name": "ShortestPaths", "size": 5914}, + {"name": "SpanningTree", "size": 3416} + ] + }, + { + "name": "optimization", + "children": [ + {"name": "AspectRatioBanker", "size": 7074} + ] + } + ] + }, + { + "name": "animate", + "children": [ + {"name": "Easing", "size": 17010}, + {"name": "FunctionSequence", "size": 5842}, + { + "name": "interpolate", + "children": [ + {"name": "ArrayInterpolator", "size": 1983}, + {"name": "ColorInterpolator", "size": 2047}, + {"name": "DateInterpolator", "size": 1375}, + {"name": "Interpolator", "size": 8746}, + {"name": "MatrixInterpolator", "size": 2202}, + {"name": "NumberInterpolator", "size": 1382}, + {"name": "ObjectInterpolator", "size": 1629}, + {"name": "PointInterpolator", "size": 1675}, + {"name": "RectangleInterpolator", "size": 2042} + ] + }, + {"name": "ISchedulable", "size": 1041}, + {"name": "Parallel", "size": 5176}, + {"name": "Pause", "size": 449}, + {"name": "Scheduler", "size": 5593}, + {"name": "Sequence", "size": 5534}, + {"name": "Transition", "size": 9201}, + {"name": "Transitioner", "size": 19975}, + {"name": "TransitionEvent", "size": 1116}, + {"name": "Tween", "size": 6006} + ] + }, + { + "name": "data", + "children": [ + { + "name": "converters", + "children": [ + {"name": "Converters", "size": 721}, + {"name": "DelimitedTextConverter", "size": 4294}, + {"name": "GraphMLConverter", "size": 9800}, + {"name": "IDataConverter", "size": 1314}, + {"name": "JSONConverter", "size": 2220} + ] + }, + {"name": "DataField", "size": 1759}, + {"name": "DataSchema", "size": 2165}, + {"name": "DataSet", "size": 586}, + {"name": "DataSource", "size": 3331}, + {"name": "DataTable", "size": 772}, + {"name": "DataUtil", "size": 3322} + ] + }, + { + "name": "display", + "children": [ + {"name": "DirtySprite", "size": 8833}, + {"name": "LineSprite", "size": 1732}, + {"name": "RectSprite", "size": 3623}, + {"name": "TextSprite", "size": 10066} + ] + }, + { + "name": "flex", + "children": [ + {"name": "FlareVis", "size": 4116} + ] + }, + { + "name": "physics", + "children": [ + {"name": "DragForce", "size": 1082}, + {"name": "GravityForce", "size": 1336}, + {"name": "IForce", "size": 319}, + {"name": "NBodyForce", "size": 10498}, + {"name": "Particle", "size": 2822}, + {"name": "Simulation", "size": 9983}, + {"name": "Spring", "size": 2213}, + {"name": "SpringForce", "size": 1681} + ] + }, + { + "name": "query", + "children": [ + {"name": "AggregateExpression", "size": 1616}, + {"name": "And", "size": 1027}, + {"name": "Arithmetic", "size": 3891}, + {"name": "Average", "size": 891}, + {"name": "BinaryExpression", "size": 2893}, + {"name": "Comparison", "size": 5103}, + {"name": "CompositeExpression", "size": 3677}, + {"name": "Count", "size": 781}, + {"name": "DateUtil", "size": 4141}, + {"name": "Distinct", "size": 933}, + {"name": "Expression", "size": 5130}, + {"name": "ExpressionIterator", "size": 3617}, + {"name": "Fn", "size": 3240}, + {"name": "If", "size": 2732}, + {"name": "IsA", "size": 2039}, + {"name": "Literal", "size": 1214}, + {"name": "Match", "size": 3748}, + {"name": "Maximum", "size": 843}, + { + "name": "methods", + "children": [ + {"name": "add", "size": 593}, + {"name": "and", "size": 330}, + {"name": "average", "size": 287}, + {"name": "count", "size": 277}, + {"name": "distinct", "size": 292}, + {"name": "div", "size": 595}, + {"name": "eq", "size": 594}, + {"name": "fn", "size": 460}, + {"name": "gt", "size": 603}, + {"name": "gte", "size": 625}, + {"name": "iff", "size": 748}, + {"name": "isa", "size": 461}, + {"name": "lt", "size": 597}, + {"name": "lte", "size": 619}, + {"name": "max", "size": 283}, + {"name": "min", "size": 283}, + {"name": "mod", "size": 591}, + {"name": "mul", "size": 603}, + {"name": "neq", "size": 599}, + {"name": "not", "size": 386}, + {"name": "or", "size": 323}, + {"name": "orderby", "size": 307}, + {"name": "range", "size": 772}, + {"name": "select", "size": 296}, + {"name": "stddev", "size": 363}, + {"name": "sub", "size": 600}, + {"name": "sum", "size": 280}, + {"name": "update", "size": 307}, + {"name": "variance", "size": 335}, + {"name": "where", "size": 299}, + {"name": "xor", "size": 354}, + {"name": "_", "size": 264} + ] + }, + {"name": "Minimum", "size": 843}, + {"name": "Not", "size": 1554}, + {"name": "Or", "size": 970}, + {"name": "Query", "size": 13896}, + {"name": "Range", "size": 1594}, + {"name": "StringUtil", "size": 4130}, + {"name": "Sum", "size": 791}, + {"name": "Variable", "size": 1124}, + {"name": "Variance", "size": 1876}, + {"name": "Xor", "size": 1101} + ] + }, + { + "name": "scale", + "children": [ + {"name": "IScaleMap", "size": 2105}, + {"name": "LinearScale", "size": 1316}, + {"name": "LogScale", "size": 3151}, + {"name": "OrdinalScale", "size": 3770}, + {"name": "QuantileScale", "size": 2435}, + {"name": "QuantitativeScale", "size": 4839}, + {"name": "RootScale", "size": 1756}, + {"name": "Scale", "size": 4268}, + {"name": "ScaleType", "size": 1821}, + {"name": "TimeScale", "size": 5833} + ] + }, + { + "name": "util", + "children": [ + {"name": "Arrays", "size": 8258}, + {"name": "Colors", "size": 10001}, + {"name": "Dates", "size": 8217}, + {"name": "Displays", "size": 12555}, + {"name": "Filter", "size": 2324}, + {"name": "Geometry", "size": 10993}, + { + "name": "heap", + "children": [ + {"name": "FibonacciHeap", "size": 9354}, + {"name": "HeapNode", "size": 1233} + ] + }, + {"name": "IEvaluable", "size": 335}, + {"name": "IPredicate", "size": 383}, + {"name": "IValueProxy", "size": 874}, + { + "name": "math", + "children": [ + {"name": "DenseMatrix", "size": 3165}, + {"name": "IMatrix", "size": 2815}, + {"name": "SparseMatrix", "size": 3366} + ] + }, + {"name": "Maths", "size": 17705}, + {"name": "Orientation", "size": 1486}, + { + "name": "palette", + "children": [ + {"name": "ColorPalette", "size": 6367}, + {"name": "Palette", "size": 1229}, + {"name": "ShapePalette", "size": 2059}, + {"name": "SizePalette", "size": 2291} + ] + }, + {"name": "Property", "size": 5559}, + {"name": "Shapes", "size": 19118}, + {"name": "Sort", "size": 6887}, + {"name": "Stats", "size": 6557}, + {"name": "Strings", "size": 22026} + ] + }, + { + "name": "vis", + "children": [ + { + "name": "axis", + "children": [ + {"name": "Axes", "size": 1302}, + {"name": "Axis", "size": 24593}, + {"name": "AxisGridLine", "size": 652}, + {"name": "AxisLabel", "size": 636}, + {"name": "CartesianAxes", "size": 6703} + ] + }, + { + "name": "controls", + "children": [ + {"name": "AnchorControl", "size": 2138}, + {"name": "ClickControl", "size": 3824}, + {"name": "Control", "size": 1353}, + {"name": "ControlList", "size": 4665}, + {"name": "DragControl", "size": 2649}, + {"name": "ExpandControl", "size": 2832}, + {"name": "HoverControl", "size": 4896}, + {"name": "IControl", "size": 763}, + {"name": "PanZoomControl", "size": 5222}, + {"name": "SelectionControl", "size": 7862}, + {"name": "TooltipControl", "size": 8435} + ] + }, + { + "name": "data", + "children": [ + {"name": "Data", "size": 20544}, + {"name": "DataList", "size": 19788}, + {"name": "DataSprite", "size": 10349}, + {"name": "EdgeSprite", "size": 3301}, + {"name": "NodeSprite", "size": 19382}, + { + "name": "render", + "children": [ + {"name": "ArrowType", "size": 698}, + {"name": "EdgeRenderer", "size": 5569}, + {"name": "IRenderer", "size": 353}, + {"name": "ShapeRenderer", "size": 2247} + ] + }, + {"name": "ScaleBinding", "size": 11275}, + {"name": "Tree", "size": 7147}, + {"name": "TreeBuilder", "size": 9930} + ] + }, + { + "name": "events", + "children": [ + {"name": "DataEvent", "size": 2313}, + {"name": "SelectionEvent", "size": 1880}, + {"name": "TooltipEvent", "size": 1701}, + {"name": "VisualizationEvent", "size": 1117} + ] + }, + { + "name": "legend", + "children": [ + {"name": "Legend", "size": 20859}, + {"name": "LegendItem", "size": 4614}, + {"name": "LegendRange", "size": 10530} + ] + }, + { + "name": "operator", + "children": [ + { + "name": "distortion", + "children": [ + {"name": "BifocalDistortion", "size": 4461}, + {"name": "Distortion", "size": 6314}, + {"name": "FisheyeDistortion", "size": 3444} + ] + }, + { + "name": "encoder", + "children": [ + {"name": "ColorEncoder", "size": 3179}, + {"name": "Encoder", "size": 4060}, + {"name": "PropertyEncoder", "size": 4138}, + {"name": "ShapeEncoder", "size": 1690}, + {"name": "SizeEncoder", "size": 1830} + ] + }, + { + "name": "filter", + "children": [ + {"name": "FisheyeTreeFilter", "size": 5219}, + {"name": "GraphDistanceFilter", "size": 3165}, + {"name": "VisibilityFilter", "size": 3509} + ] + }, + {"name": "IOperator", "size": 1286}, + { + "name": "label", + "children": [ + {"name": "Labeler", "size": 9956}, + {"name": "RadialLabeler", "size": 3899}, + {"name": "StackedAreaLabeler", "size": 3202} + ] + }, + { + "name": "layout", + "children": [ + {"name": "AxisLayout", "size": 6725}, + {"name": "BundledEdgeRouter", "size": 3727}, + {"name": "CircleLayout", "size": 9317}, + {"name": "CirclePackingLayout", "size": 12003}, + {"name": "DendrogramLayout", "size": 4853}, + {"name": "ForceDirectedLayout", "size": 8411}, + {"name": "IcicleTreeLayout", "size": 4864}, + {"name": "IndentedTreeLayout", "size": 3174}, + {"name": "Layout", "size": 7881}, + {"name": "NodeLinkTreeLayout", "size": 12870}, + {"name": "PieLayout", "size": 2728}, + {"name": "RadialTreeLayout", "size": 12348}, + {"name": "RandomLayout", "size": 870}, + {"name": "StackedAreaLayout", "size": 9121}, + {"name": "TreeMapLayout", "size": 9191} + ] + }, + {"name": "Operator", "size": 2490}, + {"name": "OperatorList", "size": 5248}, + {"name": "OperatorSequence", "size": 4190}, + {"name": "OperatorSwitch", "size": 2581}, + {"name": "SortOperator", "size": 2023} + ] + }, + {"name": "Visualization", "size": 16540} + ] + } + ] +} \ No newline at end of file diff --git a/src/libs/rc-spider/examples/mindNode.html b/src/libs/rc-spider/examples/mindNode.html new file mode 100644 index 000000000..b3a425249 --- /dev/null +++ b/src/libs/rc-spider/examples/mindNode.html @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/src/libs/rc-spider/examples/mindNode.js b/src/libs/rc-spider/examples/mindNode.js new file mode 100644 index 000000000..913b088d8 --- /dev/null +++ b/src/libs/rc-spider/examples/mindNode.js @@ -0,0 +1,6 @@ +import 'normalize.css'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import MindNode from './mindNode/index.jsx'; + +ReactDOM.render(, document.getElementById('__react-content')); diff --git a/src/libs/rc-spider/examples/mindNode/index.jsx b/src/libs/rc-spider/examples/mindNode/index.jsx new file mode 100644 index 000000000..6c6c169be --- /dev/null +++ b/src/libs/rc-spider/examples/mindNode/index.jsx @@ -0,0 +1,117 @@ +import Spider from 'rc-spider'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import uuid from 'uuid'; +import _ from 'lodash'; + +const width = 1280; +const height = 800; +const viewerWidth = window.innerWidth; +const viewerHeight = window.innerHeight; + +const { Node, Circle, Text, Link } = Spider.Shape; +window.GLOBAL_LINK_STROKE = '#ccc'; + +function getNode(name) { + return { + id: uuid.v1(), + name: name || 'New Node', + children: [] + } +} + + + +function centerNode() { + +} + +class MindNode extends React.Component { + constructor() { + super(); + this.state = { + data: null, + transform: null, + scale: 1, + } + } + nodeClick(data) { + if (data.children) { + data._children = data.children; + data.children = null; + } else { + data.children = data._children; + data._children = null; + } + this.setState({ + data: this.state.data, + transform: this.spiderTransform(data), + }); + } + nodeCreator(data) { + return ( + + + {data.name} + + ); + } + /** + * move spider to center + * @param root + */ + spiderTransform(root) { + const scale = this.state.scale; + let x = -root.x; + let y = -root.y; + y += viewerWidth / 2; + x += viewerHeight / 2; + return new Spider.Transform().translate(y, x); + } + /** + * load data... + */ + componentDidMount() { + const data = new Request('./tree.json'); + fetch(data).then(response => response.json()) + .then(response => { + this.setState({ + data: response + }); + }); + } + render() { + const root = this.state.data; + let transform = this.state.transform; + if (!root) { + return
loading...
; + } + + // compute the new height of tree + const levelWidth = [1]; + function childCount(node, level = 0) { + if (node.children && node.children.length > 0) { + if (levelWidth.length <= level + 1) levelWidth.push(0); + levelWidth[level + 1] += node.children.length; + node.children.forEach(child => childCount(child, level + 1)); + } + } + childCount(root); + const newHeight = _.max(levelWidth) * 25; + + const tree = Spider.layout.tree().size([newHeight, viewerWidth]); + const data = tree.data(root); + + if (!transform) { + transform = this.spiderTransform(root); + } + return [n.y, n.x]} + transform={transform} + nodeCreator={this.nodeCreator.bind(this)} + dataSource={data} + moveable />; + } +} + +export default MindNode; diff --git a/src/libs/rc-spider/examples/network.html b/src/libs/rc-spider/examples/network.html new file mode 100644 index 000000000..b3a425249 --- /dev/null +++ b/src/libs/rc-spider/examples/network.html @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/src/libs/rc-spider/examples/network.js b/src/libs/rc-spider/examples/network.js new file mode 100644 index 000000000..cb9973982 --- /dev/null +++ b/src/libs/rc-spider/examples/network.js @@ -0,0 +1,38 @@ +import 'normalize.css'; +import Spider from '../lib/index.js'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const width = 960; +const height = 2200; +const { Node, Circle, Text, Link, Rect} = Spider.Shape; +const { darken } = Spider.Color; + +const nodeCreator = function (data) { + const nodeWidth = Number(data.width) || 120; + return ( + + {data.text} + ); +} + +const linkCreator = function(link) { + const offset = link.offset ? link.offset.split(' ') : [0, 0, 0, 0]; + return ; +} + +window.GLOBAL_LINK_STROKE = '#ccc'; + +const data = new Request('./network.json'); +fetch(data).then(response => response.json()) + .then(response => { + // const tree = response; + // const network = Spider.layout.network().size([height, width - 160]); + // const data = network.data(response); + ReactDOM.render(, document.getElementById('__react-content')); +}); + diff --git a/src/libs/rc-spider/examples/network.json b/src/libs/rc-spider/examples/network.json new file mode 100644 index 000000000..5fb2bb5d7 --- /dev/null +++ b/src/libs/rc-spider/examples/network.json @@ -0,0 +1,36 @@ +{"nodes":[ + {"id":7,"text":"连续活跃5周及以上","color":"#e9462f","x":"350", "y": "600"}, + {"id":9,"text":"最近一周流失","color":"#a6d787","textColor":"#4b7937","x":"350", "y":"510"}, + {"id":10,"text":"连续2周流失","color":"#89bb6c","x":"350", "y":"420"}, + {"id":6,"text":"连续4周活跃","color":"#f75f48","x":"600", "y":"250"}, + {"id":11,"text":"连续3周流失","color":"#6ea454","x":"350", "y":"330"}, + {"id":5,"text":"连续3周活跃","color":"#ff7c67","x":"600", "y":"150", "width": "160"}, + {"id":2,"text":"最近一周新增用户","color":"#ffdd78","textColor":"#d69e47","x":"70", "y":"260"}, + {"id":13,"text":"连续5周以上流失","color":"#3b6629","x":"350", "y":"150"}, + {"id":4,"text":"连续2周活跃用户","color":"#ff7f3f","x":"350", "y":"30"}, + {"id":12,"text":"连续4周流失","color":"#5a8743","x": "350", "y":"240"}, + {"id":3,"text":"最近一周回流用户","color":"#66b0f3","x":"180", "y":"210"}], + "links":[ + {"to":9,"text":"9.32%","from":7, "offset": "0 -30 0 15", "color": "#a7d888"}, + {"to":10,"text":"81.95%","from":9, "offset" : "0 -30 0 15","color": "#80b864"}, + {"to":11,"text":"89.495%","from":10, "offset" : "0 -30 0 15", "color": "#6ca352"}, + {"to":9,"text":"19.88%","from":6, "color": "green", "offset": "-10 20 70 0"}, + {"to":7,"text":"80.119995%","from":6, "offset": "10 20 75 -10"}, + {"to":3,"text":"10.505%", "from":10,"clockwise": "1", "color": "#64aff2", "offset": "-70 -10 0 20"}, + {"to":3,"text":"6.985%","clockwise": "1", "from":11, "color": "#64aff2", "offset": "-70 -10 15 20"}, + {"to":9,"text":"27.73%","from":5, "color": "green", "offset": "-70 15 70 -10"}, + {"to":9,"text":"53.879997%","from":2, "color":"green", "offset": "0 20 -70 0"}, + {"to":3,"text":"1.6949999%","from":13, "color": "#64aff2", "offset": "-70 -10 0 -35","clockwise": "0"}, + {"to":13,"text":"98.305%","from":13, "color":"#2d4a19"}, + {"to":9,"text":"38.415%","loc":"450 30,450 490", "from":4, "offset": "70 0 70 -20", "color":"#6ca251","clockwise":"1"}, + {"to":6,"text":"72.27%","line":"2px","from":5, "offset": "0 15 0 -35"}, + {"to":13,"text":"94.765%","line":"2px","from":12,"offset":"0 -30 0 18", "color": "#588540"}, + {"to":4,"text":"46.120003%","from":2, "offset":"0 -30 -70 -15"}, + {"to":5,"text":"61.585%","from":4, "clockwise": "1", "offset":"70 -10 0 -35"}, + {"to":3,"text":"18.05%","from":9,"clockwise":"1", "color":"#63aff4", "offset":"-70 -20 -20 20"}, + {"to":3,"text":"5.235%","clockwise":"1", "color":"#63aff4","from":12, "offset":"-65 0 70 -10"}, + {"to":9,"text":"62.995%","from":3, "color":"#62944b", "offset":"-40 20 -70 -10"}, + {"to":12,"text":"93.015%","from":11, "offset":"0 -30 0 20", "color": "#578641"}, + {"to":7,"text":"90.68%","line":"2px","revert":true, "from":7}, + {"to":4,"text":"37.005%","from":3,"offset": "-10 -30 -70"}] +} \ No newline at end of file diff --git a/src/libs/rc-spider/examples/pattern-journey.html b/src/libs/rc-spider/examples/pattern-journey.html new file mode 100644 index 000000000..48cdce852 --- /dev/null +++ b/src/libs/rc-spider/examples/pattern-journey.html @@ -0,0 +1 @@ +placeholder diff --git a/src/libs/rc-spider/examples/pattern-journey.js b/src/libs/rc-spider/examples/pattern-journey.js new file mode 100644 index 000000000..86f69c6fb --- /dev/null +++ b/src/libs/rc-spider/examples/pattern-journey.js @@ -0,0 +1,56 @@ +import 'normalize.css'; +import Spider from 'rc-spider'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const width = 960; +const height = 2200; +const { Node, Circle, Text, Link, Rect} = Spider.Shape; +const { darken } = Spider.Color; + +const nodeCreator = function (data) { + const nodeWidth = Number(data.width) || 150; + const nodeHeight = Number(data.height) || 50; + return ( alert(data.info)}> + + {data.text} + ); +} + +const linkCreator = function(link) { + const offset = link.offset ? link.offset.split(' ') : [0, 0, 0, 0]; + const textOffset = link.textOffset ? link.textOffset.split(' ') : [0, 0]; + return ; +} + +window.GLOBAL_LINK_STROKE = '#ccc'; + +const data = new Request('./pattern-journey.json'); +fetch(data).then(response => response.json()) + .then(response => { + // translate coordinates + response.nodes = response.nodes.map(item => { + item.x = parseInt(item.x) + 450; + // item.text = `${item.id} ${item.text}`; + return item; + }) + // const tree = response; + // const network = Spider.layout.network().size([height, width - 160]); + // const data = network.data(response); + ReactDOM.render(, document.getElementById('__react-content')); +}); + diff --git a/src/libs/rc-spider/examples/pattern-journey.json b/src/libs/rc-spider/examples/pattern-journey.json new file mode 100644 index 000000000..6d2a0dfd7 --- /dev/null +++ b/src/libs/rc-spider/examples/pattern-journey.json @@ -0,0 +1,234 @@ +{ + "nodes": [ + { + "id": 10, + "text": "Is the component in\nthe libtrary?", + "color": "#00baf2", + "x": "0", + "y": "50", + "info": "You can search for patterns at the pattern library website. If you don't find anything suitable, you can also ask other people in the Mattermost channel." + }, + { + "id": 20, + "text": "Does it fulfill\nall requirements?", + "color": "#fcaf17", + "width": 175, + "x": "-325", + "y": "125", + "info": "Study the pattern documentation at the Pattern Library website and all the examples provided. This way, you can understand if the pattern is suitable for your specific task." + }, + { + "id": 30, + "text": "Anything similar\nat other projects?", + "color": "#54bc7b", + "width": 175, + "x": "325", + "y": "125", + "info": "Ask around if people at other projects implement anything similar? You can instantly ask in Mattermost channel or raise this quesion in regular Design or Develoment meetings. Also, you can ask people directly." + }, + { + "id": 40, + "text": "Use it!", + "color": "#54bc7b", + "height": 40, + "x": "-100", + "y": "525", + "info": "The component you were searching for is in Pattern Library. Check out its latest version and use according to the documentation." + }, + { + "id": 50, + "text": "Can it be amended to suit\n your new requirements while still\n fitting existing requirements?", + "color": "#54bc7b", + "width": 225, + "height": 68, + "x": "-150", + "y": "200", + "info": "Figure out the requirements for the existing component based on the documentation and examples. If you have doubts, ask in Mattermost or in person. Does it look that you can provide changes and the component will not be broken in the places it is used now?" + }, + { + "id": 60, + "text": "Implement\n the component", + "color": "#ff7f3f", + "x": "-100", + "y": "400", + "info": "It seems that you need to add this pattern into Pattern Library. So start this project, raise a task in JIRA project. Follow the workflow for implementing new patterns which includes JIRA practises, communication standards and code flow." + }, + { + "id": 80, + "text": "Can you take it as it is?", + "color": "#fcaf17", + "x": "175", + "y": "200", + "width": 175, + "height": 36, + "info": "Is the code of existing component exactly as you need or you would provide some changes into it?" + }, + { + "id": 90, + "text": "Do other teams ready to use\n new altered version?", + "color": "#00baf2", + "width": 200, + "x": "50", + "y": "300", + "info": "If you change the existing component so that it meets your requirements, do the current users of it able to use the altered version? Ask them directly or raise this question publically." + }, + { + "id": 100, + "text": "Can it be used by other\nprojects in the future", + "color": "#ff7f3f", + "width": 175, + "x": "300", + "y": "300", + "info": "Is there future need for such component at other projects? Discuss this with different teams, preferably in public channels or at common meetings." + }, + { + "id": 110, + "text": "Implement \nin your project", + "color": "#767677", + "width": 125, + "x": "200", + "y": "475", + "info": "Looks like you need to implement the pattern in your own project, not as a part of the library. However, it still can be added into the library later once someone else will be looking for similar solution." + } + ], + "links": [ + { + "from": 10, + "to": 20, + "text": "yes", + "color": "#00a950", + "offset": "0 -6 0 -25", + "textOffset": "75 -15", + "clockwise": "0" + }, + { + "from": 10, + "to": 30, + "text": "no", + "color": "#ee4444", + "offset": "0 -6 0 -25", + "textOffset": "-75 -15", + "clockwise": "1" + }, + { + "from": 20, + "to": 40, + "text": "yes", + "color": "#00a950", + "offset": "0 0 -75 -5", + "textOffset": "-15 -225" + }, + { + "from": 20, + "to": 50, + "text": "no", + "color": "#ee4444", + "offset": "0 -6 0 -25", + "textOffset": "10 -15", + "clockwise": "1" + }, + { + "from": 50, + "to": 60, + "text": "yes", + "color": "#00a950", + "offset": "-60 0 -75 -5", + "textOffset": "-15 -50" + }, + { + "from": 60, + "to": 40, + "text": "wait for\n release", + "offset": "0 0 0 -25", + "textOffset": "-13 5", + "rotate": "-90", + "color": "#00a950" + }, + { + "from": 30, + "to": 80, + "text": "yes", + "color": "#00a950", + "offset": "0 0 25 -25", + "textOffset": "-25 -15", + "clockwise": "0" + }, + { + "from": 80, + "to": 60, + "text": "yes", + "color": "#00a950", + "offset": "0 0 75 -10", + "textOffset": "-5 -150" + }, + { + "from": 80, + "to": 90, + "text": "no", + "color": "#ee4444", + "offset": "-25 -5 -10 -25", + "textOffset": "5 -15", + "clockwise": "0" + }, + { + "from": 50, + "to": 90, + "text": "no", + "color": "#ee4444", + "offset": "0 -5 -30 -25", + "textOffset": "10 -15", + "clockwise": "1" + }, + { + "from": 90, + "to": 60, + "text": "yes", + "color": "#00a950", + "offset": "0 -5 0 -25", + "textOffset": "-10 -15", + "clockwise": "0" + }, + { + "from": 30, + "to": 100, + "text": "no", + "color": "#ee4444", + "offset": "20 0 45 -25", + "textOffset": "10 -42" + }, + { + "from": 100, + "to": 60, + "text": "yes", + "color": "#00a950", + "offset": "-10 0 75 10", + "textOffset": "90 -75" + }, + { + "from": 100, + "to": 110, + "text": "no", + "color": "#ee4444", + "offset": "10 0 65 -10", + "textOffset": "15 -65" + }, + { + "from": 90, + "to": 110, + "text": "no", + "color": "#ee4444", + "offset": "25 0 -60 0", + "textOffset": "15 -80" + }, + { + "from": 110, + "to": 30, + "text": "one day it will be there...", + "color": "#e0e0e1", + "offset": "0 10 80 25", + "textOffset": "5 -25", + "rotate": "-90", + "clockwise": "0" + } + ] +} diff --git a/src/libs/rc-spider/examples/simple.html b/src/libs/rc-spider/examples/simple.html new file mode 100644 index 000000000..b3a425249 --- /dev/null +++ b/src/libs/rc-spider/examples/simple.html @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/src/libs/rc-spider/examples/simple.js b/src/libs/rc-spider/examples/simple.js new file mode 100644 index 000000000..5f73e9a0c --- /dev/null +++ b/src/libs/rc-spider/examples/simple.js @@ -0,0 +1,31 @@ +import 'normalize.css'; +import Spider from 'rc-spider'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const width = 960; +const height = 2200; +const { Node, Circle, Text} = Spider.Shape; + +const nodeCreator = function (data) { + return ( + + {data.name} + ); +} + +window.GLOBAL_LINK_STROKE = '#ccc'; + +const data = new Request('./flare.json'); +fetch(data).then(response => response.json()) + .then(response => { + const tree = response; + const cluster = Spider.layout.cluster().size([height, width - 160]); + const data = cluster.data(tree); + ReactDOM.render( [d.y, d.x]} + nodeCreator={nodeCreator} + />, document.getElementById('__react-content')); +}); + diff --git a/src/libs/rc-spider/examples/tree.html b/src/libs/rc-spider/examples/tree.html new file mode 100644 index 000000000..b3a425249 --- /dev/null +++ b/src/libs/rc-spider/examples/tree.html @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/src/libs/rc-spider/examples/tree.js b/src/libs/rc-spider/examples/tree.js new file mode 100644 index 000000000..0577eb0df --- /dev/null +++ b/src/libs/rc-spider/examples/tree.js @@ -0,0 +1,31 @@ +import 'normalize.css'; +import Spider from 'rc-spider'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +const width = 1200; +const height = 3000; +const { Node, Circle, Text} = Spider.Shape; + +const nodeCreator = function (data) { + return ( + + {data.name} + ); +} + +window.GLOBAL_LINK_STROKE = '#ccc'; + +const data = new Request('https://raw.githubusercontent.com/unruledboy/WebFrontEndStack/master/ux/WebFrontEndStack.json'); +fetch(data).then(response => response.json()) + .then(response => { + const tree = response; + const cluster = Spider.layout.tree().size([height, width - 160]); + const data = cluster.data(tree); + ReactDOM.render( [d.y, d.x]} + nodeCreator={nodeCreator} + />, document.getElementById('__react-content')); +}); + diff --git a/src/libs/rc-spider/examples/tree.json b/src/libs/rc-spider/examples/tree.json new file mode 100644 index 000000000..115621d75 --- /dev/null +++ b/src/libs/rc-spider/examples/tree.json @@ -0,0 +1,30 @@ +{ + "name": "analytics", + "children": [ + { + "name": "cluster", + "children": [ + {"name": "AgglomerativeCluster", "size": 3938}, + {"name": "CommunityStructure", "size": 3812}, + {"name": "HierarchicalCluster", "size": 6714}, + {"name": "MergeEdge", "size": 743} + ] + }, + { + "name": "graph", + "children": [ + {"name": "BetweennessCentrality", "size": 3534}, + {"name": "LinkDistance", "size": 5731}, + {"name": "MaxFlowMinCut", "size": 7840}, + {"name": "ShortestPaths", "size": 5914}, + {"name": "SpanningTree", "size": 3416} + ] + }, + { + "name": "optimization", + "children": [ + {"name": "AspectRatioBanker", "size": 7074} + ] + } + ] +} \ No newline at end of file diff --git a/src/libs/rc-spider/index.js b/src/libs/rc-spider/index.js new file mode 100644 index 000000000..a47a51d5b --- /dev/null +++ b/src/libs/rc-spider/index.js @@ -0,0 +1,3 @@ +// export this package's api +import Spider from './src'; +export default Spider; diff --git a/src/libs/rc-spider/lib/Spider.js b/src/libs/rc-spider/lib/Spider.js new file mode 100644 index 000000000..8412ec36a --- /dev/null +++ b/src/libs/rc-spider/lib/Spider.js @@ -0,0 +1,334 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _reactDom = require('react-dom'); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +var _SpiderBase2 = require('./base/SpiderBase'); + +var _SpiderBase3 = _interopRequireDefault(_SpiderBase2); + +var _shapes = require('./shapes'); + +var _shapes2 = _interopRequireDefault(_shapes); + +var _color = require('./color'); + +var _color2 = _interopRequireDefault(_color); + +var _reactArt = require('react-art'); + +var _reactArt2 = _interopRequireDefault(_reactArt); + +var _layout = require('./layout'); + +var _layout2 = _interopRequireDefault(_layout); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Group = _reactArt2["default"].Group; +var Transform = _reactArt2["default"].Transform; +var Surface = _reactArt2["default"].Surface; + +function defaultNodeCreator(data) { + return _react2["default"].createElement( + _shapes.Node, + { margin: '10', width: '20', height: '20', data: data }, + _react2["default"].createElement(_shapes.Circle, null) + ); +} + +function defaultLinkCreator(link) { + return _react2["default"].createElement(_shapes.Link, { data: link }); +} + +function defaultProjection(element) { + return [element.x, element.y]; +} + +function defaultTransform() { + return new Transform(); +} + +var Spider = function (_SpiderBase) { + _inherits(Spider, _SpiderBase); + + function Spider(props) { + _classCallCheck(this, Spider); + + var _this = _possibleConstructorReturn(this, _SpiderBase.call(this, props)); + + var _this$loadDataSource = _this.loadDataSource(props.dataSource, props.nodeCreator, props.linkCreator), + nodes = _this$loadDataSource.nodes, + links = _this$loadDataSource.links; + + _this.state = { + dataSource: props.dataSource, + nodes: nodes, + links: links, + dragging: false, + lastX: 0, + lastY: 0, + left: 0, + top: 0 + }; + return _this; + } + + Spider.prototype.loadDataSource = function loadDataSource(dataSource, nodeCreator, linkCreator) { + if (Object.keys(dataSource).length === 0) { + return { + nodes: [], + links: [] + }; + } + var nodes = this.nodes(dataSource); + var links = this.links(linkCreator); + + return { + nodes: nodes, + links: links + }; + }; + + Spider.prototype.update = function update(id, newNode) { + var nodes = this.state.nodes; + + var updatedNodes = nodes.set(id, newNode); + this.setState({ + nodes: updatedNodes + }); + }; + + Spider.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { + var dataSource = nextProps.dataSource; + + var _loadDataSource = this.loadDataSource(dataSource, nextProps.nodeCreator, nextProps.linkCreator), + nodes = _loadDataSource.nodes, + links = _loadDataSource.links; + + this.setState({ + dataSource: dataSource, + nodes: nodes, + links: links + }); + }; + + Spider.prototype.enableDrag = function enableDrag(ev) { + var position = ev.targetTouches && ev.targetTouches[0] || ev; + + this.setState({ + dragging: true, + lastX: position.clientX, + lastY: position.clientY + }); + }; + + Spider.prototype.handleMouseMove = function handleMouseMove(ev) { + var position = ev.targetTouches && ev.targetTouches[0] || ev; + if (!this.state.dragging) { + return; + } + var deltaX = position.clientX - this.state.lastX; + var deltaY = position.clientY - this.state.lastY; + this.setState({ + lastX: position.clientX, + lastY: position.clientY, + left: deltaX, + top: deltaY + }); + }; + + Spider.prototype.handleDragStop = function handleDragStop() { + this.setState({ + dragging: false, + lastX: 0, + lastY: 0, + left: 0, + top: 0 + }); + }; + + Spider.prototype.componentDidMount = function componentDidMount() { + if (this.props.moveable) { + window.addEventListener('mousedown', this.enableDrag.bind(this)); + window.addEventListener('mousemove', this.handleMouseMove.bind(this)); + window.addEventListener('mouseup', this.handleDragStop.bind(this)); + } + }; + + Spider.prototype.toggleChild = function toggleChild(node) { + var _this2 = this; + + return function () { + var nodes = _this2.updateNode(node, { + expand: !node.expand + }); + _this2.layout(); + var links = _this2.links(_this2.props.linkCreator); + _this2.setState({ + nodes: nodes, + links: links + }); + }; + }; + + Spider.prototype.nodeMouseOver = function nodeMouseOver() { + _reactDom2["default"].findDOMNode(this.refs.cursorHelper).style.cursor = 'pointer'; + }; + + Spider.prototype.nodeMouseOut = function nodeMouseOut() { + _reactDom2["default"].findDOMNode(this.refs.cursorHelper).style.cursor = 'default'; + }; + + Spider.prototype.renderNodes = function renderNodes() { + var _this3 = this; + + var nodes = this.state.nodes; + var _props = this.props, + nodeCreator = _props.nodeCreator, + nodeTransform = _props.nodeTransform; + + var nodeProjection = this.props.nodeProjection || this.props.projection; + return nodes.toKeyedSeq().map(function (node) { + var projectedNode = nodeProjection(node); + var groupTransform = void 0; + if (nodeTransform) { + groupTransform = nodeTransform({ + x: projectedNode[0], + y: projectedNode[1] + }); + } else { + groupTransform = new Transform().translate(projectedNode[0], projectedNode[1]); + } + return _react2["default"].createElement( + Group, + { className: 'node', key: 'node-' + node.id, transform: groupTransform, + onMouseOver: _this3.nodeMouseOver.bind(_this3), + onMouseOut: _this3.nodeMouseOut.bind(_this3) + }, + node._display ? _react2["default"].Children.map(nodeCreator(node), function (children) { + return _react2["default"].cloneElement(children, { data: node }); + }, _this3) : null + ); + }); + }; + + Spider.prototype.renderLinks = function renderLinks() { + var _this4 = this; + + var links = this.state.links; + var linkCreator = this.props.linkCreator; + + return links.toKeyedSeq().map(function (link, idx) { + return _react2["default"].createElement( + Group, + { key: 'link-' + idx }, + _react2["default"].Children.map(linkCreator(link), _this4.passProjection, _this4) + ); + }); + }; + + Spider.prototype.passProjection = function passProjection(child) { + var props = child.props; + + var cloneProps = { + data: props.data, + projection: props.projection || this.props.linkProjection || this.props.projection, + stroke: props.stroke || this.props.stroke || window.GLOBAL_LINK_STROKE, + strokeWidth: props.strokeWidth || this.props.strokeWidth || window.GLOBAL_LINK_STROKE_WIDTH + }; + return _react2["default"].cloneElement(child, cloneProps); + }; + + Spider.prototype.render = function render() { + var _props2 = this.props, + width = _props2.width, + height = _props2.height, + offset = _props2.offset, + transform = _props2.transform; + var _state = this.state, + left = _state.left, + top = _state.top; + + + var offsetLeft = offset && offset[0] || 0; + var offsetTop = offset && offset[1] || 0; + var nodes = this.renderNodes(); + var links = this.renderLinks(); + + var transformFunction = transform || new Transform(); + var groupTransform = transformFunction.translate(left + offsetLeft, top + offsetTop); + // node width + return _react2["default"].createElement( + 'div', + { ref: 'cursorHelper' }, + _react2["default"].createElement( + Surface, + { width: width, height: height, ref: 'canvas' }, + _react2["default"].createElement( + Group, + { transform: groupTransform }, + links.valueSeq(), + nodes.valueSeq() + ) + ) + ); + }; + + return Spider; +}(_SpiderBase3["default"]); + +Spider.propTypes = { + offset: _propTypes2["default"].array, // 整个图的偏移 + transform: _propTypes2["default"].object, // 指定 node 的 transform + projection: _propTypes2["default"].func, // 指定一个 node 和 link 的映射函数 + nodeProjection: _propTypes2["default"].func, // 指定 node 的映射函数 + linkProjection: _propTypes2["default"].func, + startX: _propTypes2["default"].number, + startY: _propTypes2["default"].number, + enableDrag: _propTypes2["default"].bool, + enableWheel: _propTypes2["default"].bool, + direction: _propTypes2["default"].string, + lineType: _propTypes2["default"].string, + width: _propTypes2["default"].number, + height: _propTypes2["default"].number, + dataSource: _propTypes2["default"].object.isRequired, + nodeCreator: _propTypes2["default"].func, + linkCreator: _propTypes2["default"].func +}; + +Spider.defaultProps = { + projection: defaultProjection, + transform: defaultTransform(), + nodeCreator: defaultNodeCreator, + linkCreator: defaultLinkCreator +}; + +Spider.Shape = _shapes2["default"]; +Spider.layout = _layout2["default"]; +Spider.Transform = Transform; +Spider.Color = _color2["default"]; + +exports["default"] = Spider; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/base/Node.js b/src/libs/rc-spider/lib/base/Node.js new file mode 100644 index 000000000..48742a5ab --- /dev/null +++ b/src/libs/rc-spider/lib/base/Node.js @@ -0,0 +1,148 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _global = require('./global'); + +var _global2 = _interopRequireDefault(_global); + +var _uuid = require('uuid'); + +var _uuid2 = _interopRequireDefault(_uuid); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var GLOBAL_NODE_WIDTH = _global2["default"].GLOBAL_NODE_WIDTH, + GLOBAL_NODE_HEIGHT = _global2["default"].GLOBAL_NODE_HEIGHT, + GLOBAL_NODE_MARGIN = _global2["default"].GLOBAL_NODE_MARGIN; +/** + * class Node + * + * A node has : + */ + +var Node = function () { + function Node(data, spider) { + _classCallCheck(this, Node); + + _extends(this, data); + this.x = Number(this.x); + this.y = Number(this.y); + this.controlPoints(this.x, this.y, 'horizontal'); + this.id = data.id || _uuid2["default"].v1(); + this.__data = data; + this.__inDegree = 0; + this.__outDegree = 0; + this.__spider = spider; + // this.render( nodeCreator ); + this.expand = data.expand || true; + this._display = this.expand; + this.children = []; + data.id = data.id || this.id; + data.expand = data.expand === undefined || data.expand === null ? this.expand : data.expand; + } + + Node.prototype.render = function render(nodeCreator) { + var data = this.__data; + this._key = _uuid2["default"].v1(); + this._el = nodeCreator(data, this.__spider); + this.__width = Number(data.width || this._el.props.width) || GLOBAL_NODE_WIDTH; + this.__height = Number(data.height || this._el.props.height) || GLOBAL_NODE_HEIGHT; + this.__margin = Number(this._el.props.margin) || GLOBAL_NODE_MARGIN; + this.entry_radius = this._el.props.entry_radius || 0; + this.exit_radius = this._el.props.exit_radius || 0; + this.expand = data.expand === undefined || data.expand === null ? this.expand : data.expand; + return this._el; + }; + + Node.prototype.isRoot = function isRoot() { + return !this.__inDegree; + }; + + Node.prototype.isLeaf = function isLeaf() { + return !this.__outDegree; + }; + + Node.prototype.getDegree = function getDegree() { + return this.__inDegree + this.__outDegree; + }; + + Node.prototype.getEntryRadius = function getEntryRadius(direction) { + return Number(this.entry_radius || (direction === 'vertical' ? this.__height / 2 : this.__width / 2)); + }; + + Node.prototype.getExitRadius = function getExitRadius(direction) { + return Number(this.exit_radius || (direction === 'vertical' ? this.__height / 2 : this.__width / 2)); + }; + + Node.prototype.show = function show() { + this._display = true; + }; + + Node.prototype.hide = function hide() { + this._display = false; + }; + + Node.prototype.controlPoints = function controlPoints(x, y, direction) { + var entryRadius = this.getEntryRadius(direction); + var exitRadius = this.getExitRadius(direction); + + this.i_x = this.o_x = x; + this.i_y = this.o_y = y; + if (direction === 'vertical') { + if (entryRadius) { + this.i_x = x; + this.i_y = y - entryRadius; + } + + if (exitRadius) { + this.o_x = x; + this.o_y = y + exitRadius; + } + } else { + if (entryRadius) { + this.i_x = x - entryRadius; + this.i_y = y; + } + + if (exitRadius) { + this.o_x = x + exitRadius; + this.o_y = y; + } + } + }; + + Node.prototype._afterLayout = function _afterLayout(x, y) { + this.x = x; + this.y = y; + }; + + Node.prototype._afterChildrenLayout = function _afterChildrenLayout(x, y) { + this.x = x; + this.y = y; + }; + + Node.prototype.get = function get(key) { + return this.__data[key]; + }; + + Node.prototype.set = function set(target) { + // avoid to modify id of node + if (target.id) { + delete target.id; + } + _extends(this, target); + this.__spider.update(this.id, this); + }; + + return Node; +}(); + +exports["default"] = Node; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/base/SpiderBase.js b/src/libs/rc-spider/lib/base/SpiderBase.js new file mode 100644 index 000000000..b0dd0777a --- /dev/null +++ b/src/libs/rc-spider/lib/base/SpiderBase.js @@ -0,0 +1,113 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _dataLoader = require('../dataLoader'); + +var _dataLoader2 = _interopRequireDefault(_dataLoader); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var SpiderBase = function (_React$Component) { + _inherits(SpiderBase, _React$Component); + + function SpiderBase() { + _classCallCheck(this, SpiderBase); + + return _possibleConstructorReturn(this, _React$Component.apply(this, arguments)); + } + + SpiderBase.prototype.getTreeRoot = function getTreeRoot() { + if (this.__root) { + return this.__root; + } + var data = this.__data; + return data.nodes.find(function (node) { + return node.__inDegree === 0; + }); + }; + /** + * updateNode will always make spider relayout.. + * otherwise manual set `relayout` attribute of attributes to `false` + * @param targetNode + * @param attributes + */ + + + SpiderBase.prototype.updateNode = function updateNode(targetNode, attributes) { + var nodes = this.__data.nodes; + var nodeToUpdate = nodes.get(targetNode.id); + _extends(nodeToUpdate.__data, attributes); + nodeToUpdate.render(this.props.nodeCreator); + var updatedNodes = this.__data.nodes.set(targetNode.id, nodeToUpdate); + this.__data.nodes = updatedNodes; + return updatedNodes; + }; + + SpiderBase.prototype.data = function data(rawData) { + var data = (0, _dataLoader2["default"])(rawData, this); + this.__data = data; + }; + + SpiderBase.prototype.nodes = function nodes(data) { + this.data(data); + return this.__data.nodes; + }; + + SpiderBase.prototype.layout = function layout() { + this.normalizeNodes(); + }; + + SpiderBase.prototype.normalizeNodes = function normalizeNodes() { + var _this2 = this; + + var data = this.__data; + var root = this.getTreeRoot(); + var rootX = root.x; + var rootY = root.y; + var boundWidth = root.rect.width; + var boundHeight = root.rect.height; + this.__data.nodes = data.nodes.map(function (node) { + var x = (node.x - rootX) / boundWidth * _this2.props.width; + var y = (node.y - rootY) / boundHeight * _this2.props.height + _this2.props.height / 2; + node._afterLayout(x, y); + node.controlPoints(x, y, 'horizontal'); + return node; + }); + }; + + SpiderBase.prototype.links = function links() { + return this.__data.links; + }; + + return SpiderBase; +}(_react2["default"].Component); + +SpiderBase.propTypes = { + nodeCreator: _propTypes2["default"].func, + width: _propTypes2["default"].any, + height: _propTypes2["default"].any +}; + +exports["default"] = SpiderBase; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/base/Util.js b/src/libs/rc-spider/lib/base/Util.js new file mode 100644 index 000000000..ffb7e8d87 --- /dev/null +++ b/src/libs/rc-spider/lib/base/Util.js @@ -0,0 +1,132 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.defaultProjection = defaultProjection; +exports.diagonal = diagonal; +exports.separation = separation; +exports.broke = broke; +exports.hierarchyVisitAfter = hierarchyVisitAfter; +function defaultProjection(item) { + return [item.x, item.y]; +} + +function normalizeOffset() { + var originOffset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + var offset = []; + for (var i = 0; i < 4; i++) { + offset[i] = Number(originOffset[i]) || 0; + } + return offset; +} + +function diagonal(link, projection, offset) { + var _offset = normalizeOffset(offset); + projection = projection || defaultProjection; + var p0 = { + x: link.source.x + _offset[0], + y: link.source.y + _offset[1] + }; + var p3 = { + x: link.target.x + _offset[2], + y: link.target.y + _offset[3] + }; + var mid = (p0.y + p3.y) / 2; + var points = [p0, { x: p0.x, y: mid }, { x: p3.x, y: mid }, p3].map(projection); + return { + points: points, + path: 'M' + points[0] + 'C' + points[1] + ' ' + points[2] + ' ' + points[3] + }; +} + +function separation(left, right) { + return left.parent === right.parent ? 1 : 2; +} + +function broke(link, projection, offset) { + var _offset = normalizeOffset(offset); + projection = projection || defaultProjection; + var p0 = { + x: link.source.x + _offset[0], + y: link.source.y + _offset[1] + }; + var p3 = { + x: link.target.x + _offset[2], + y: link.target.y + _offset[3] + }; + + var points = []; + + if (p0.x !== p3.x && p0.y !== p3.y) { + points = [p0, { + x: link.clockwise ? p3.x : p0.x, + y: link.clockwise ? p0.y : p3.y + }, p3].map(projection); + var midPoint = points[1]; + var nextPoint = points[2]; + var lastPoint = points[0]; + var cx = midPoint[0]; + var cy = midPoint[1]; + var predeltaX = cx === lastPoint[0] ? 0 : Math.ceil((cx - lastPoint[0]) / Math.abs(cx - lastPoint[0])); + + var predeltaY = cy === lastPoint[1] ? 0 : Math.ceil((cy - lastPoint[1]) / Math.abs(cy - lastPoint[1])); + + var nextdeltaX = cx === nextPoint[0] ? 0 : Math.ceil((nextPoint[0] - cx) / Math.abs(nextPoint[0] - cx)); + + var nextdeltaY = cy === nextPoint[1] ? 0 : Math.ceil((nextPoint[1] - cy) / Math.abs(nextPoint[1] - cy)); + + var clockwise = null; + if (link.clockwise !== undefined) { + clockwise = link.clockwise; + } else { + clockwise = nextPoint[0] > lastPoint[0] && nextPoint[1] > lastPoint[1] ? '0' : '1'; + } + var r1 = { x: cx - 30 * predeltaX, y: cy - 30 * predeltaY }; + var r2 = { x: cx + 30 * nextdeltaX, y: cy + 30 * nextdeltaY }; + var radius = 'L' + r1.x + ' ' + r1.y + 'A 30 30 0 0 ' + clockwise + ' ' + r2.x + ' ' + r2.y; + + return { + points: [p0, r1, r2, p3].map(projection), + path: 'M' + points[0] + radius + 'L' + points[2] + }; + } + if (link.source === link.target) { + // connect to itself + var revert = link.revert ? 15 : -30; + var tx = p0.x; + var ty = p0.y + revert; + var path = 'M' + (tx - 20) + ' ' + ty + 'A 24 24 0 1 ' + (link.revert ? 0 : 1) + ' ' + (tx + 20) + ' ' + ty; + points = [{ x: p0.x - 20, y: p0.y }, { x: p0.x + 20, y: p0.y }].map(projection); + return { + points: points, + path: path + }; + } + points = [p0, p3].map(projection); + return { + points: points, + path: 'M' + points[0] + 'L' + points[1] + }; +} + +function hierarchyVisitAfter(node, callback) { + var nodes = [node]; + var nodes2 = []; + + while (nodes.length) { + var currentNode = nodes.pop(); + currentNode.__level__ = currentNode.parent ? currentNode.parent.__level__ + 1 : 0; + nodes2.push(currentNode); + if (currentNode.children && currentNode.children.length) { + for (var i = 0; i < currentNode.children.length; i++) { + currentNode.children[i].parent = currentNode; + nodes.push(currentNode.children[i]); + } + } + } + while (nodes2.length) { + callback(nodes2.pop()); + } +} \ No newline at end of file diff --git a/src/libs/rc-spider/lib/base/global.js b/src/libs/rc-spider/lib/base/global.js new file mode 100644 index 000000000..8b120c61c --- /dev/null +++ b/src/libs/rc-spider/lib/base/global.js @@ -0,0 +1,21 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var globalConfig = { + GLOBAL_NODE_WIDTH: 5, + GLOBAL_NODE_HEIGHT: 5, + GLOBAL_NODE_MARGIN: 5 +}; + +if (typeof window !== 'undefined') { + window.NODE_DEFAULT_FILL = window.NODE_DEFAULT_FILL || 'white'; + window.NODE_DEFAULT_STROKE = window.NODE_DEFAULT_STROKE || 'black'; + window.NODE_DEFAULT_STROKE_WIDTH = window.NODE_DEFAULT_STROKE_WIDTH || '1'; + window.GLOBAL_LINK_STROKE = window.GLOBAL_LINK_STROKE || 'black'; + window.GLOBAL_LINK_STROKE_WIDTH = window.GLOBAL_LINK_STROKE_WIDTH || '1'; + window.TEXT_DEFAULT_COLOR = window.TEXT_DEFAULT_COLOR || 'black'; +} +exports["default"] = globalConfig; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/color/index.js b/src/libs/rc-spider/lib/color/index.js new file mode 100644 index 000000000..5ae86cbf1 --- /dev/null +++ b/src/libs/rc-spider/lib/color/index.js @@ -0,0 +1,28 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _color = require('color'); + +var _color2 = _interopRequireDefault(_color); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var SpiderColor = function () { + function SpiderColor() { + _classCallCheck(this, SpiderColor); + } + + SpiderColor.prototype.darken = function darken(colorString, alpha) { + return (0, _color2["default"])(colorString).darken(alpha).hexString(); + }; + + return SpiderColor; +}(); + +exports["default"] = new SpiderColor(); +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/dataLoader/index.js b/src/libs/rc-spider/lib/dataLoader/index.js new file mode 100644 index 000000000..62b37143b --- /dev/null +++ b/src/libs/rc-spider/lib/dataLoader/index.js @@ -0,0 +1,135 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +exports["default"] = dataLoader; + +var _immutable = require('immutable'); + +var _Node = require('../base/Node'); + +var _Node2 = _interopRequireDefault(_Node); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +/** + * loadArrayData + * @param data + * @returns {{nodes: *, links: *}} + */ +function loadArrayData(arr, spider) { + var nodeMap = {}; + var linkMap = {}; + // 把所有节点放置到map里 + arr.forEach(function (data) { + nodeMap[data.id] = new _Node2["default"](data, spider); + }); + + arr.forEach(function (data) { + var currentNode = nodeMap[data.id]; + if (nodeMap[data.id] && nodeMap[data.parent]) { + var parentNode = nodeMap[data.parent]; + + var source = parentNode; + var target = currentNode; + var key = source.id + '-' + target.id; + linkMap[key] = { + source: source, target: target + }; + parentNode.__outDegree += 1; + parentNode.children.push(currentNode); + currentNode.__inDegree += 1; + } + }); + return { + nodes: new _immutable.Iterable(nodeMap), + links: new _immutable.Iterable(linkMap) + }; +} +/** + * 加载图的数据 + * @param data + * @param spider + */ +function loadGraphData(data, spider) { + var nodeMap = {}; + var linkMap = {}; + data.nodes.map(function (rawNode) { + var node = new _Node2["default"](rawNode, spider); + nodeMap[node.id] = node; + }); + data.links.map(function (rawLink) { + var key = rawLink.from + '-' + rawLink.to; + var source = nodeMap[rawLink.from]; + var target = nodeMap[rawLink.to]; + linkMap[key] = _extends({ + source: source, + target: target + }, rawLink); + }); + return { + nodes: new _immutable.Iterable(nodeMap), + links: new _immutable.Iterable(linkMap) + }; +} +/** + * loadStructuralData + * 加载结构化的数据 + * @param data + * @returns {*} + */ +function loadStructuralData(data, spider) { + var nodeMap = {}; + var linkMap = {}; + var currentData = data; + + function readNode(nodeData, parent) { + var node = new _Node2["default"](nodeData, spider); + + nodeMap[node.id] = node; + + if (parent) { + var source = parent; + var target = node; + var key = source.id + '-' + target.id; + linkMap[key] = { + source: source, target: target + }; + parent.__outDegree += 1; + node.parent = parent; + node.__inDegree += 1; + } + + if (nodeData.children && nodeData.children.length) { + nodeData.children.forEach(function (child) { + readNode(child, nodeData); + }); + } + } + + readNode(currentData); + return { + nodes: new _immutable.Iterable(nodeMap), + links: new _immutable.Iterable(linkMap) + }; +} +/** + * dataLoader + * @param data + */ +function dataLoader(data, spider) { + if (Array.isArray(data)) { + return loadArrayData(data, spider); + } + if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === 'object' && data.nodes && data.links) { + return loadGraphData(data, spider); + } + return loadStructuralData(data, spider); +} +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/index.js b/src/libs/rc-spider/lib/index.js new file mode 100644 index 000000000..055b7293d --- /dev/null +++ b/src/libs/rc-spider/lib/index.js @@ -0,0 +1,15 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Spider = require('./Spider'); + +var _Spider2 = _interopRequireDefault(_Spider); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +exports["default"] = _Spider2["default"]; // export this package's api + +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/layout/base.js b/src/libs/rc-spider/lib/layout/base.js new file mode 100644 index 000000000..ba3397d1a --- /dev/null +++ b/src/libs/rc-spider/lib/layout/base.js @@ -0,0 +1,28 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Layout = function () { + function Layout() { + _classCallCheck(this, Layout); + } + + Layout.prototype.size = function size(sizeArray) { + this.size = sizeArray; + return this; + }; + + Layout.prototype.projection = function projection(projectionFunc) { + this.projectionFunc = projectionFunc; + return this; + }; + + return Layout; +}(); + +exports["default"] = Layout; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/layout/cluster.js b/src/libs/rc-spider/lib/layout/cluster.js new file mode 100644 index 000000000..4c1a22c6d --- /dev/null +++ b/src/libs/rc-spider/lib/layout/cluster.js @@ -0,0 +1,98 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Util = require('../base/Util'); + +var _lodash = require('lodash'); + +var _lodash2 = _interopRequireDefault(_lodash); + +var _base = require('./base'); + +var _base2 = _interopRequireDefault(_base); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +function clusterX(children) { + return children.reduce(function (x, child) { + return x + child.x; + }, 0) / children.length; +} + +function clusterY(children) { + return 1 + _lodash2["default"].max(children.map(function (child) { + return child.y; + })); +} + +function clusterLeft(node) { + var children = node.children; + return children && children.length ? clusterLeft(children[0]) : node; +} + +function clusterRight(node) { + var children = node.children; + return children && children.length ? clusterRight(children[children.length - 1]) : node; +} + +var Cluster = function (_LayoutBase) { + _inherits(Cluster, _LayoutBase); + + function Cluster() { + _classCallCheck(this, Cluster); + + return _possibleConstructorReturn(this, _LayoutBase.apply(this, arguments)); + } + + Cluster.prototype.data = function data(root) { + var previousNode = void 0; + var x = 0; + var size = this.size; + var projectionFunc = this.projectionFunc; + + (0, _Util.hierarchyVisitAfter)(root, function (node) { + var children = node.children; + if (children && children.length) { + node.x = clusterX(children); + node.y = clusterY(children); + } else { + node.x = previousNode ? x += (0, _Util.separation)(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + + var left = clusterLeft(root); + var right = clusterRight(root); + var x0 = left.x - (0, _Util.separation)(left, right) / 2; + var x1 = right.x + (0, _Util.separation)(right, left) / 2; + (0, _Util.hierarchyVisitAfter)(root, function (node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + + // projection .. + if (projectionFunc) { + var projectioned = projectionFunc(node); + node.x = projectioned[0]; + node.y = projectioned[1]; + } + }); + return root; + }; + + return Cluster; +}(_base2["default"]); + +exports["default"] = Cluster; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/layout/index.js b/src/libs/rc-spider/lib/layout/index.js new file mode 100644 index 000000000..f9c499375 --- /dev/null +++ b/src/libs/rc-spider/lib/layout/index.js @@ -0,0 +1,16 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var layout = {}; + +['cluster', 'tree'].forEach(function (item) { + var LayoutClass = require('./' + item); + layout[item] = function () { + return new LayoutClass(); + }; +}); + +exports["default"] = layout; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/layout/tree.js b/src/libs/rc-spider/lib/layout/tree.js new file mode 100644 index 000000000..7138162de --- /dev/null +++ b/src/libs/rc-spider/lib/layout/tree.js @@ -0,0 +1,206 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Util = require('../base/Util'); + +var _lodash = require('lodash'); + +var _lodash2 = _interopRequireDefault(_lodash); + +var _base = require('./base'); + +var _base2 = _interopRequireDefault(_base); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Tree = function (_LayoutBase) { + _inherits(Tree, _LayoutBase); + + function Tree() { + _classCallCheck(this, Tree); + + var _this = _possibleConstructorReturn(this, _LayoutBase.call(this)); + + _this.levelIndexes = []; + _this.maxDeep = 0; + _this.minX = 0; + _this.maxX = 0; + return _this; + } + + Tree.prototype.walkLevel = function walkLevel(node) { + var _this2 = this; + + var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + + if (this.levelIndexes.length < level + 1) { + this.levelIndexes.push([]); + } + + var indexes = this.levelIndexes[level]; + indexes.push(node); + if (!node.children || node.children.length === 0) { + node.__depth = 1; + } else { + node.children.forEach(function (child) { + return _this2.walkLevel(child, level + 1); + }); + node.__depth = _lodash2["default"].max(node.children.map(function (child) { + return child.__depth; + })) + 1; + } + this.maxDeep = Math.max(node.__depth, this.maxDeep); + node.__left_bound = new Float32Array(node.__depth); + node.__right_bound = new Float32Array(node.__depth); + }; + + Tree.prototype.walkRelative = function walkRelative() { + var _this3 = this; + + for (var level = this.levelIndexes.length - 1; level >= 0; level--) { + var nodes = this.levelIndexes[level]; + nodes.forEach(function (node) { + if (node.__depth === 1) { + node.__left_bound[0] = -1; + node.__right_bound[0] = 1; + } else { + _this3.move(node.children, node); + } + }); + } + }; + + Tree.prototype.move = function move(children, node) { + var activeNode = children[0]; + var firstNode = children[0]; + var mLevel = void 0; + var cLevel = void 0; + var leftBounds = void 0; + var rightBounds = void 0; + + var firstNodeLeftBound = firstNode.__left_bound; + var firstNodeRightBound = firstNode.__right_bound; + var len = children.length - 1; + + var _len = node.__depth - 1; + var left = new Float32Array(_len); + var right = new Float32Array(_len); + + var maxR = void 0; + var tmp = void 0; + + left.fill(0xfffffff0); + + firstNode.x = 0; + + for (var j = 0; j < firstNode.__depth; j++) { + right[j] = firstNodeRightBound[j]; + left[j] = firstNodeLeftBound[j]; + } + + mLevel = firstNode.__depth; + + for (var i = 0; i <= len; i++) { + activeNode = children[i]; + cLevel = mLevel > activeNode.__depth ? activeNode.__depth : mLevel; + mLevel = mLevel > activeNode.__depth ? mLevel : activeNode.__depth; + + leftBounds = activeNode.__left_bound; + rightBounds = activeNode.__right_bound; + maxR = 0; + + for (var _j = 0; _j < cLevel; _j++) { + tmp = right[_j] - leftBounds[_j]; + if (maxR < tmp) { + maxR = tmp; + } + } + + activeNode.x = maxR; + + for (var _j2 = 0; _j2 < activeNode.__depth; _j2++) { + right[_j2] = maxR + rightBounds[_j2]; + tmp = maxR + leftBounds[_j2]; + if (tmp < left[_j2]) { + left[_j2] = tmp; + } + } + } + + var center = (children[len].x + children[0].x) / 2; + children.forEach(function (child) { + return child.x -= center; + }); + + var currentRightBounds = node.__right_bound; + var currentLeftBounds = node.__left_bound; + currentLeftBounds[0] = -1; + currentRightBounds[0] = 1; + for (var _j3 = 1; _j3 < node.__depth; _j3++) { + currentRightBounds[_j3] = right[_j3 - 1] - center; + currentLeftBounds[_j3] = left[_j3 - 1] - center; + } + }; + + Tree.prototype.walkAbsolute = function walkAbsolute(ele, px) { + var _this4 = this; + + var children = ele.children; + if (children && children.length) { + children.forEach(function (child) { + var x = child.x || 0; + x = x + px; + child.x = x; + _this4.minX = Math.min(_this4.minX, x); + _this4.maxX = Math.max(_this4.maxX, x); + if (child.children && child.children.length) { + _this4.walkAbsolute(child, x); + } + }); + } + }; + + Tree.prototype.data = function data(root) { + var _this5 = this; + + var size = this.size; + var projectionFunc = this.projectionFunc; + + root.x = 0; + root.y = 0; + + this.walkLevel(root); + this.walkRelative(); + this.walkAbsolute(root, 0); + + var x0 = this.minX - 1; + var x1 = this.maxX + 1; + (0, _Util.hierarchyVisitAfter)(root, function (node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (node.__level__ ? node.__level__ / _this5.maxDeep : 0) * size[1]; + + if (projectionFunc) { + var projectioned = projectionFunc(node); + node.x = projectioned[0]; + node.y = projectioned[1]; + } + }); + return root; + }; + + return Tree; +}(_base2["default"]); + +exports["default"] = Tree; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Circle.js b/src/libs/rc-spider/lib/shapes/Circle.js new file mode 100644 index 000000000..02e50444d --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Circle.js @@ -0,0 +1,56 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _Shape2 = require('./Shape'); + +var _Shape3 = _interopRequireDefault(_Shape2); + +var _Circle = require('react-art/Circle'); + +var _Circle2 = _interopRequireDefault(_Circle); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Circle = function (_Shape) { + _inherits(Circle, _Shape); + + function Circle() { + _classCallCheck(this, Circle); + + return _possibleConstructorReturn(this, _Shape.apply(this, arguments)); + } + + Circle.prototype.render = function render() { + var _props = this.props, + radius = _props.radius, + fill = _props.fill, + stroke = _props.stroke, + strokeWidth = _props.strokeWidth, + onClick = _props.onClick; + + return _react2["default"].createElement(_Circle2["default"], { radius: Number(radius), fill: fill, + stroke: stroke, strokeWidth: strokeWidth, + onClick: onClick + }); + }; + + return Circle; +}(_Shape3["default"]); + +exports["default"] = Circle; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Link.js b/src/libs/rc-spider/lib/shapes/Link.js new file mode 100644 index 000000000..769d788dc --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Link.js @@ -0,0 +1,107 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _reactArt = require('react-art'); + +var _reactArt2 = _interopRequireDefault(_reactArt); + +var _Text = require('./Text'); + +var _Text2 = _interopRequireDefault(_Text); + +var _Util = require('../base/Util'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Group = _reactArt2["default"].Group; + +var Shape = _reactArt2["default"].Shape; +var Transform = _reactArt2["default"].Transform; + +var Link = function (_Component) { + _inherits(Link, _Component); + + function Link() { + _classCallCheck(this, Link); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + Link.prototype.render = function render() { + var projection = this.props.projection; + var _props = this.props, + data = _props.data, + text = _props.text, + stroke = _props.stroke, + strokeWidth = _props.strokeWidth, + offset = _props.offset, + textOffset = _props.textOffset, + rotate = _props.rotate, + arrow = _props.arrow; + var source = data.source, + target = data.target; + // default theme style + + var pathId = 'link-path-' + source.id + '-' + target.id; + var path = this.props.type === 'broke' ? (0, _Util.broke)(data, projection, offset) : (0, _Util.diagonal)(data, projection, offset); + var svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + svgPath.setAttribute('d', path.path); + var midPoint = svgPath.getPointAtLength(Math.ceil(svgPath.getTotalLength() / 2)); + midPoint.x += parseInt(textOffset[0], 10); + midPoint.y += parseInt(textOffset[1], 10); + svgPath.remove(); + var points = path.points; + var movePoint = points[points.length - 1]; + var lastPoint = points[points.length - 2]; + var alpha = Math.atan((movePoint[1] - lastPoint[1]) / (movePoint[0] - lastPoint[0])) / Math.PI * 2; + alpha = isNaN(alpha) ? 0 : (alpha + 1) * (movePoint[0] > lastPoint[0] ? 90 : -90); + var transform = new Transform().translate(movePoint[0], movePoint[1]).rotate(alpha); + return _react2["default"].createElement( + Group, + { key: pathId }, + _react2["default"].createElement(Shape, { d: path.path, stroke: stroke, strokeWidth: strokeWidth }), + arrow ? _react2["default"].createElement(Shape, { d: 'M-4.5,10L0.5,0L5.5,10', fill: stroke, transform: transform }) : null, + _react2["default"].createElement( + _Text2["default"], + { color: stroke, offset: [midPoint.x, midPoint.y], rotate: rotate, alignment: 'middle' }, + text + ) + ); + }; + + return Link; +}(_react.Component); + +Link.propTypes = { + projection: _propTypes2["default"].func, + data: _propTypes2["default"].object, + offset: _propTypes2["default"].array, + textOffset: _propTypes2["default"].array, + text: _propTypes2["default"].string, + stroke: _propTypes2["default"].string, + arrow: _propTypes2["default"]["boolean"], + strokeWidth: _propTypes2["default"].string, + type: _propTypes2["default"].string +}; + +exports["default"] = Link; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Node.js b/src/libs/rc-spider/lib/shapes/Node.js new file mode 100644 index 000000000..33fd2fd85 --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Node.js @@ -0,0 +1,94 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _Shape2 = require('./Shape'); + +var _Shape3 = _interopRequireDefault(_Shape2); + +var _reactArt = require('react-art'); + +var _reactArt2 = _interopRequireDefault(_reactArt); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Group = _reactArt2["default"].Group; +var Transform = _reactArt2["default"].Transform; + +var Node = function (_Shape) { + _inherits(Node, _Shape); + + function Node() { + _classCallCheck(this, Node); + + return _possibleConstructorReturn(this, _Shape.apply(this, arguments)); + } + + Node.prototype.renderTreeNode = function renderTreeNode(child, index) { + var props = this.props; + var cloneProps = { + key: child.props.key || index, + width: child.props.width || props.width, + height: child.props.height || props.height, + fill: child.props.fill || props.fill || window.NODE_DEFAULT_FILL, + stroke: child.props.stroke || props.stroke || window.NODE_DEFAULT_STROKE, + strokeWidth: child.props.strokeWidth || props.strokeWidth || window.NODE_DEFAULT_STROKE_WIDTH + }; + if (child.type.name === 'Circle') { + cloneProps.radius = child.props.radius || Math.min(cloneProps.width, cloneProps.height); + } + if (child.type.name === 'Text') { + cloneProps.color = child.props.color || props.fill || window.TEXT_DEFAULT_COLOR; + } + + return _react2["default"].cloneElement(child, cloneProps); + }; + + Node.prototype.nodeClick = function nodeClick() { + if (this.props.onClick) { + this.props.onClick.call(this, this.props.data.__data); + } + }; + + Node.prototype.render = function render() { + var _props = this.props, + children = _props.children, + offset = _props.offset; + + var groupTransform = new Transform(); + groupTransform.translate(offset[0], offset[1]); + return _react2["default"].createElement( + Group, + { className: 'node', transform: groupTransform, onClick: this.nodeClick.bind(this) }, + _react2["default"].Children.map(children, this.renderTreeNode, this) + ); + }; + + return Node; +}(_Shape3["default"]); + +Node.propTypes = { + width: _propTypes2["default"].any.isRequired, + height: _propTypes2["default"].any.isRequired +}; + +exports["default"] = Node; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Rect.js b/src/libs/rc-spider/lib/shapes/Rect.js new file mode 100644 index 000000000..883755f5b --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Rect.js @@ -0,0 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _reactArt = require('react-art'); + +var _reactArt2 = _interopRequireDefault(_reactArt); + +var _Rectangle = require('react-art/Rectangle'); + +var _Rectangle2 = _interopRequireDefault(_Rectangle); + +var _Shape2 = require('./Shape'); + +var _Shape3 = _interopRequireDefault(_Shape2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Group = _reactArt2["default"].Group; +var Transform = _reactArt2["default"].Transform; + +var Rect = function (_Shape) { + _inherits(Rect, _Shape); + + function Rect() { + _classCallCheck(this, Rect); + + return _possibleConstructorReturn(this, _Shape.apply(this, arguments)); + } + + Rect.prototype.render = function render() { + var _props = this.props, + offset = _props.offset, + transform = _props.transform, + width = _props.width, + height = _props.height, + color = _props.color, + radius = _props.radius, + stroke = _props.stroke, + strokeWidth = _props.strokeWidth; + + var rectTransform = transform || new Transform(); + rectTransform.translate(offset[0], offset[1]); + return _react2["default"].createElement( + Group, + null, + _react2["default"].createElement(_Rectangle2["default"], { + transform: rectTransform, + radius: radius, + width: width, + height: height, + stroke: stroke, + fill: color, + strokeWidth: strokeWidth + }), + this.props.children + ); + }; + + return Rect; +}(_Shape3["default"]); + +_react2["default"].defaultProps = { + radius: 0 +}; + +exports["default"] = Rect; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Shape.js b/src/libs/rc-spider/lib/shapes/Shape.js new file mode 100755 index 000000000..6f1113a5f --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Shape.js @@ -0,0 +1,42 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Shape = function (_React$Component) { + _inherits(Shape, _React$Component); + + function Shape(props) { + _classCallCheck(this, Shape); + + return _possibleConstructorReturn(this, _React$Component.call(this, props)); + } + + Shape.prototype.render = function render() {}; + + return Shape; +}(_react2["default"].Component); + +Shape.defaultProps = { + offset: [0, 0], + stroke: null, + strokeWidth: 1 +}; + +exports["default"] = Shape; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/Text.js b/src/libs/rc-spider/lib/shapes/Text.js new file mode 100644 index 000000000..4c5b4b9c4 --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/Text.js @@ -0,0 +1,72 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _Shape2 = require('./Shape'); + +var _Shape3 = _interopRequireDefault(_Shape2); + +var _reactArt = require('react-art'); + +var _reactArt2 = _interopRequireDefault(_reactArt); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } + +var Transform = _reactArt2["default"].Transform; +var ArtText = _reactArt2["default"].Text; + +var Text = function (_Shape) { + _inherits(Text, _Shape); + + function Text() { + _classCallCheck(this, Text); + + return _possibleConstructorReturn(this, _Shape.apply(this, arguments)); + } + + Text.prototype.render = function render() { + var _props = this.props, + offset = _props.offset, + children = _props.children, + color = _props.color, + transform = _props.transform, + rotate = _props.rotate, + alignment = _props.alignment, + size = _props.size; + + + var textTransform = transform || new Transform(); + textTransform.translate(offset[0], offset[1]); + rotate && textTransform.rotate(rotate); + return _react2["default"].createElement( + ArtText, + { transform: textTransform, fill: color, + alignment: alignment || 'left', + font: { fontSize: size, fontWeight: 100 } + }, + children + ); + }; + + return Text; +}(_Shape3["default"]); + +Text.defaultProps = { + offset: [0, 0] +}; +exports["default"] = Text; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/shapes/index.js b/src/libs/rc-spider/lib/shapes/index.js new file mode 100755 index 000000000..c0bc8e548 --- /dev/null +++ b/src/libs/rc-spider/lib/shapes/index.js @@ -0,0 +1,36 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Link = require('./Link'); + +var _Link2 = _interopRequireDefault(_Link); + +var _Node = require('./Node'); + +var _Node2 = _interopRequireDefault(_Node); + +var _Circle = require('./Circle'); + +var _Circle2 = _interopRequireDefault(_Circle); + +var _Text = require('./Text'); + +var _Text2 = _interopRequireDefault(_Text); + +var _Rect = require('./Rect'); + +var _Rect2 = _interopRequireDefault(_Rect); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +exports["default"] = { + Link: _Link2["default"], + Node: _Node2["default"], + Circle: _Circle2["default"], + Rect: _Rect2["default"], + Text: _Text2["default"] +}; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/libs/rc-spider/lib/theme/default.js b/src/libs/rc-spider/lib/theme/default.js new file mode 100644 index 000000000..9a390c31f --- /dev/null +++ b/src/libs/rc-spider/lib/theme/default.js @@ -0,0 +1 @@ +"use strict"; \ No newline at end of file diff --git a/src/libs/rc-spider/package.json b/src/libs/rc-spider/package.json new file mode 100644 index 000000000..6106bc0b3 --- /dev/null +++ b/src/libs/rc-spider/package.json @@ -0,0 +1,61 @@ +{ + "name": "rc-spider", + "version": "0.0.8", + "description": "spider ui component for react", + "keywords": [ + "react", + "react-component", + "react-spider", + "spider" + ], + "homepage": "https://github.com/react-component/spider", + "author": "surgesoft@gmail.com", + "repository": { + "type": "git", + "url": "https://github.com/react-component/spider.git" + }, + "bugs": { + "url": "https://github.com/react-component/spider/issues" + }, + "files": [ + "lib", + "assets/*.css" + ], + "licenses": "MIT", + "main": "./lib/index", + "config": { + "port": 8000 + }, + "scripts": { + "build": "rc-tools run build", + "compile": "rc-tools run compile", + "gh-pages": "rc-tools run gh-pages", + "start": "rc-tools run server", + "pub": "rc-tools run pub", + "lint": "rc-tools run lint", + "karma": "rc-tools run karma", + "saucelabs": "rc-tools run saucelabs", + "test": "rc-tools run test", + "chrome-test": "rc-tools run chrome-test", + "coverage": "rc-tools run coverage" + }, + "devDependencies": { + "eslint": "^2.3.0", + "eslint-config-airbnb": "^6.1.0", + "eslint-plugin-react": "^4.2.1", + "expect.js": "0.3.x", + "pre-commit": "1.x", + "rc-tools": "5.x", + "react": "16.4.1", + "react-addons-test-utils": "16.4.1", + "react-dom": "16.4.1" + }, + "dependencies": { + "color": "^0.11.1", + "immutable": "^3.7.6", + "lodash": "^4.6.1", + "prop-types": "^15.6.2", + "react-art": "^16.4.1", + "uuid": "^2.0.1" + } +} diff --git a/src/libs/rc-spider/src/Spider.jsx b/src/libs/rc-spider/src/Spider.jsx new file mode 100644 index 000000000..53eb2310d --- /dev/null +++ b/src/libs/rc-spider/src/Spider.jsx @@ -0,0 +1,249 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import ReactDOM from 'react-dom'; +import SpiderBase from './base/SpiderBase'; +import Shape, { Link, Node, Circle } from './shapes'; +import Color from './color'; +import ReactART from 'react-art'; +const Group = ReactART.Group; +const Transform = ReactART.Transform; +const Surface = ReactART.Surface; + + +import layout from './layout'; + +function defaultNodeCreator(data) { + return ( + + ); +} + +function defaultLinkCreator(link) { + return (); +} + +function defaultProjection(element) { + return [element.x, element.y]; +} + +function defaultTransform() { + return new Transform(); +} + +class Spider extends SpiderBase { + constructor(props) { + super(props); + const { nodes, links } = this.loadDataSource( + props.dataSource, + props.nodeCreator, + props.linkCreator); + this.state = { + dataSource: props.dataSource, + nodes, + links, + dragging: false, + lastX: 0, + lastY: 0, + left: 0, + top: 0, + }; + } + + loadDataSource(dataSource, nodeCreator, linkCreator) { + if (Object.keys(dataSource).length === 0) { + return { + nodes: [], + links: [], + }; + } + const nodes = this.nodes(dataSource); + const links = this.links(linkCreator); + + return { + nodes, + links, + }; + } + + update(id, newNode) { + const { nodes } = this.state; + const updatedNodes = nodes.set(id, newNode); + this.setState({ + nodes: updatedNodes, + }); + } + componentWillReceiveProps(nextProps) { + const { dataSource } = nextProps; + const { nodes, links } = this.loadDataSource( + dataSource, + nextProps.nodeCreator, + nextProps.linkCreator); + this.setState({ + dataSource, + nodes, + links, + }); + } + enableDrag(ev) { + const position = (ev.targetTouches && ev.targetTouches[0]) || ev; + + this.setState({ + dragging: true, + lastX: position.clientX, + lastY: position.clientY, + }); + } + + handleMouseMove(ev) { + const position = (ev.targetTouches && ev.targetTouches[0]) || ev; + if (!this.state.dragging) { + return; + } + const deltaX = position.clientX - this.state.lastX; + const deltaY = position.clientY - this.state.lastY; + this.setState({ + lastX: position.clientX, + lastY: position.clientY, + left: deltaX, + top: deltaY, + }); + } + + handleDragStop() { + this.setState({ + dragging: false, + lastX: 0, + lastY: 0, + left: 0, + top: 0, + }); + } + + componentDidMount() { + if (this.props.moveable) { + window.addEventListener('mousedown', this.enableDrag.bind(this)); + window.addEventListener('mousemove', this.handleMouseMove.bind(this)); + window.addEventListener('mouseup', this.handleDragStop.bind(this)); + } + } + + toggleChild(node) { + return () => { + const nodes = this.updateNode(node, { + expand: !node.expand, + }); + this.layout(); + const links = this.links(this.props.linkCreator); + this.setState({ + nodes, + links, + }); + }; + } + nodeMouseOver() { + ReactDOM.findDOMNode(this.refs.cursorHelper).style.cursor = 'pointer'; + } + + nodeMouseOut() { + ReactDOM.findDOMNode(this.refs.cursorHelper).style.cursor = 'default'; + } + renderNodes() { + const nodes = this.state.nodes; + const { nodeCreator, nodeTransform } = this.props; + const nodeProjection = this.props.nodeProjection || this.props.projection; + return nodes.toKeyedSeq().map((node) => { + const projectedNode = nodeProjection(node); + let groupTransform; + if (nodeTransform) { + groupTransform = nodeTransform({ + x: projectedNode[0], + y: projectedNode[1], + }); + } else { + groupTransform = new Transform().translate(projectedNode[0], projectedNode[1]); + } + return ( + { node._display ? React.Children.map(nodeCreator(node), children => { + return React.cloneElement(children, { data: node }); + }, this) : null } + ); + }); + } + renderLinks() { + const links = this.state.links; + const { linkCreator } = this.props; + return links.toKeyedSeq().map((link, idx) => + + {React.Children.map(linkCreator(link), this.passProjection, this)} + + ); + } + passProjection(child) { + const { props } = child; + const cloneProps = { + data: props.data, + projection: props.projection || this.props.linkProjection || this.props.projection, + stroke: props.stroke || this.props.stroke || window.GLOBAL_LINK_STROKE, + strokeWidth: props.strokeWidth || this.props.strokeWidth || window.GLOBAL_LINK_STROKE_WIDTH, + }; + return React.cloneElement(child, cloneProps); + } + render() { + const { width, height, offset, transform } = this.props; + const { left, top } = this.state; + + const offsetLeft = offset && offset[0] || 0; + const offsetTop = offset && offset[1] || 0; + const nodes = this.renderNodes(); + const links = this.renderLinks(); + + const transformFunction = transform || new Transform(); + const groupTransform = transformFunction.translate(left + offsetLeft, top + offsetTop); + // node width + return (
+ + + {links.valueSeq()} + {nodes.valueSeq()} + + +
); + } +} + +Spider.propTypes = { + offset: PropTypes.array, // 整个图的偏移 + transform: PropTypes.object, // 指定 node 的 transform + projection: PropTypes.func, // 指定一个 node 和 link 的映射函数 + nodeProjection: PropTypes.func, // 指定 node 的映射函数 + linkProjection: PropTypes.func, + startX: PropTypes.number, + startY: PropTypes.number, + enableDrag: PropTypes.bool, + enableWheel: PropTypes.bool, + direction: PropTypes.string, + lineType: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + dataSource: PropTypes.object.isRequired, + nodeCreator: PropTypes.func, + linkCreator: PropTypes.func, +}; + +Spider.defaultProps = { + projection: defaultProjection, + transform: defaultTransform(), + nodeCreator: defaultNodeCreator, + linkCreator: defaultLinkCreator, +}; + +Spider.Shape = Shape; +Spider.layout = layout; +Spider.Transform = Transform; +Spider.Color = Color; + +export default Spider; diff --git a/src/libs/rc-spider/src/base/Node.js b/src/libs/rc-spider/src/base/Node.js new file mode 100644 index 000000000..eeea7eeb1 --- /dev/null +++ b/src/libs/rc-spider/src/base/Node.js @@ -0,0 +1,123 @@ +import globalConfig from './global'; +import uuid from 'uuid'; +const { GLOBAL_NODE_WIDTH, GLOBAL_NODE_HEIGHT, GLOBAL_NODE_MARGIN } = globalConfig; +/** + * class Node + * + * A node has : + */ +class Node { + constructor(data, spider) { + Object.assign(this, data); + this.x = Number(this.x); + this.y = Number(this.y); + this.controlPoints(this.x, this.y, 'horizontal'); + this.id = data.id || uuid.v1(); + this.__data = data; + this.__inDegree = 0; + this.__outDegree = 0; + this.__spider = spider; + // this.render( nodeCreator ); + this.expand = data.expand || true; + this._display = this.expand; + this.children = []; + data.id = data.id || this.id; + data.expand = (data.expand === undefined || data.expand === null) ? this.expand : data.expand; + } + + render(nodeCreator) { + const data = this.__data; + this._key = uuid.v1(); + this._el = nodeCreator(data, this.__spider); + this.__width = Number(data.width || this._el.props.width) || GLOBAL_NODE_WIDTH; + this.__height = Number(data.height || this._el.props.height) || GLOBAL_NODE_HEIGHT; + this.__margin = Number(this._el.props.margin) || GLOBAL_NODE_MARGIN; + this.entry_radius = this._el.props.entry_radius || 0; + this.exit_radius = this._el.props.exit_radius || 0; + this.expand = (data.expand === undefined || data.expand === null) ? this.expand : data.expand; + return this._el; + } + + isRoot() { + return !this.__inDegree; + } + + isLeaf() { + return !this.__outDegree; + } + + getDegree() { + return this.__inDegree + this.__outDegree; + } + + getEntryRadius(direction) { + return Number(this.entry_radius || + (direction === 'vertical' ? this.__height / 2 : this.__width / 2)); + } + + getExitRadius(direction) { + return Number(this.exit_radius || + (direction === 'vertical' ? this.__height / 2 : this.__width / 2)); + } + + show() { + this._display = true; + } + + hide() { + this._display = false; + } + controlPoints(x, y, direction) { + const entryRadius = this.getEntryRadius(direction); + const exitRadius = this.getExitRadius(direction); + + this.i_x = this.o_x = x; + this.i_y = this.o_y = y; + if (direction === 'vertical') { + if (entryRadius) { + this.i_x = x; + this.i_y = y - entryRadius; + } + + if (exitRadius) { + this.o_x = x; + this.o_y = y + exitRadius; + } + } else { + if (entryRadius) { + this.i_x = x - entryRadius; + this.i_y = y; + } + + if (exitRadius) { + this.o_x = x + exitRadius; + this.o_y = y; + } + } + } + + _afterLayout(x, y) { + this.x = x; + this.y = y; + } + + _afterChildrenLayout(x, y) { + this.x = x; + this.y = y; + } + + get(key) { + return this.__data[key]; + } + + set(target) { + // avoid to modify id of node + if (target.id) { + delete target.id; + } + Object.assign(this, target); + this.__spider.update(this.id, this); + } +} + +export default Node; diff --git a/src/libs/rc-spider/src/base/SpiderBase.jsx b/src/libs/rc-spider/src/base/SpiderBase.jsx new file mode 100644 index 000000000..53a3a3b2c --- /dev/null +++ b/src/libs/rc-spider/src/base/SpiderBase.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import dataLoader from '../dataLoader'; +import PropTypes from 'prop-types'; + +class SpiderBase extends React.Component { + getTreeRoot() { + if (this.__root) { + return this.__root; + } + const data = this.__data; + return data.nodes.find(node => node.__inDegree === 0); + } + /** + * updateNode will always make spider relayout.. + * otherwise manual set `relayout` attribute of attributes to `false` + * @param targetNode + * @param attributes + */ + updateNode(targetNode, attributes) { + const nodes = this.__data.nodes; + const nodeToUpdate = nodes.get(targetNode.id); + Object.assign(nodeToUpdate.__data, attributes); + nodeToUpdate.render(this.props.nodeCreator); + const updatedNodes = this.__data.nodes.set(targetNode.id, nodeToUpdate); + this.__data.nodes = updatedNodes; + return updatedNodes; + } + + data(rawData) { + const data = dataLoader(rawData, this); + this.__data = data; + } + + nodes(data) { + this.data(data); + return this.__data.nodes; + } + + layout() { + this.normalizeNodes(); + } + + normalizeNodes() { + const data = this.__data; + const root = this.getTreeRoot(); + const rootX = root.x; + const rootY = root.y; + const boundWidth = root.rect.width; + const boundHeight = root.rect.height; + this.__data.nodes = data.nodes.map(node => { + const x = (node.x - rootX) / boundWidth * this.props.width; + const y = (node.y - rootY) / boundHeight * this.props.height + this.props.height / 2; + node._afterLayout(x, y); + node.controlPoints(x, y, 'horizontal'); + return node; + }); + } + + links() { + return this.__data.links; + } +} + +SpiderBase.propTypes = { + nodeCreator: PropTypes.func, + width: PropTypes.any, + height: PropTypes.any, +}; + +export default SpiderBase; diff --git a/src/libs/rc-spider/src/base/Util.js b/src/libs/rc-spider/src/base/Util.js new file mode 100644 index 000000000..357598bb2 --- /dev/null +++ b/src/libs/rc-spider/src/base/Util.js @@ -0,0 +1,129 @@ + +export function defaultProjection(item) { + return [item.x, item.y]; +} + +function normalizeOffset(originOffset = []) { + const offset = []; + for (let i = 0; i < 4; i++) { + offset[i] = Number(originOffset[i]) || 0; + } + return offset; +} + +export function diagonal(link, projection, offset) { + const _offset = normalizeOffset(offset); + projection = projection || defaultProjection; + const p0 = { + x: link.source.x + _offset[0], + y: link.source.y + _offset[1], + }; + const p3 = { + x: link.target.x + _offset[2], + y: link.target.y + _offset[3], + }; + const mid = (p0.y + p3.y) / 2; + const points = [p0, { x: p0.x, y: mid }, { x: p3.x, y: mid }, p3].map(projection); + return { + points, + path: `M${points[0]}C${points[1]} ${points[2]} ${points[3]}`, + }; +} + +export function separation(left, right) { + return left.parent === right.parent ? 1 : 2; +} + +export function broke(link, projection, offset) { + const _offset = normalizeOffset(offset); + projection = projection || defaultProjection; + const p0 = { + x: link.source.x + _offset[0], + y: link.source.y + _offset[1], + }; + const p3 = { + x: link.target.x + _offset[2], + y: link.target.y + _offset[3], + }; + + let points = []; + + if (p0.x !== p3.x && p0.y !== p3.y) { + points = [p0, { + x: link.clockwise ? p3.x : p0.x, + y: link.clockwise ? p0.y : p3.y, + }, p3].map(projection); + const midPoint = points[1]; + const nextPoint = points[2]; + const lastPoint = points[0]; + const cx = midPoint[0]; + const cy = midPoint[1]; + const predeltaX = cx === lastPoint[0] + ? 0 + : Math.ceil((cx - lastPoint[0]) / Math.abs(cx - lastPoint[0])); + + const predeltaY = cy === lastPoint[1] + ? 0 + : Math.ceil((cy - lastPoint[1]) / Math.abs(cy - lastPoint[1])); + + const nextdeltaX = cx === nextPoint[0] + ? 0 + : Math.ceil((nextPoint[0] - cx) / Math.abs(nextPoint[0] - cx)); + + const nextdeltaY = cy === nextPoint[1] + ? 0 + : Math.ceil((nextPoint[1] - cy) / Math.abs(nextPoint[1] - cy)); + + let clockwise = null; + if (link.clockwise !== undefined) { + clockwise = link.clockwise; + } else { + clockwise = (nextPoint[0] > lastPoint[0] && nextPoint[1] > lastPoint[1]) ? '0' : '1'; + } + const r1 = { x: cx - 30 * predeltaX, y: cy - 30 * predeltaY }; + const r2 = { x: cx + 30 * nextdeltaX, y: cy + 30 * nextdeltaY }; + const radius = `L${r1.x} ${r1.y}A 30 30 0 0 ${clockwise} ${r2.x} ${r2.y}`; + + return { + points: [p0, r1, r2, p3].map(projection), + path: `M${points[0]}${radius}L${points[2]}`, + }; + } + if (link.source === link.target) { + // connect to itself + const revert = link.revert ? 15 : -30; + const tx = p0.x; + const ty = p0.y + revert; + const path = `M${tx - 20} ${ty}A 24 24 0 1 ${link.revert ? 0 : 1} ${tx + 20} ${ty}`; + points = [{ x: p0.x - 20, y: p0.y }, { x: p0.x + 20, y: p0.y }].map(projection); + return { + points, + path, + }; + } + points = [p0, p3].map(projection); + return { + points, + path: `M${points[0]}L${points[1]}`, + }; +} + +export function hierarchyVisitAfter(node, callback) { + const nodes = [node]; + const nodes2 = []; + + while (nodes.length) { + const currentNode = nodes.pop(); + currentNode.__level__ = currentNode.parent ? currentNode.parent.__level__ + 1 : 0; + nodes2.push(currentNode); + if (currentNode.children && currentNode.children.length) { + for (let i = 0; i < currentNode.children.length; i++) { + currentNode.children[i].parent = currentNode; + nodes.push(currentNode.children[i]); + } + } + } + while (nodes2.length) { + callback(nodes2.pop()); + } +} diff --git a/src/libs/rc-spider/src/base/global.js b/src/libs/rc-spider/src/base/global.js new file mode 100644 index 000000000..37c6d51a0 --- /dev/null +++ b/src/libs/rc-spider/src/base/global.js @@ -0,0 +1,15 @@ +const globalConfig = { + GLOBAL_NODE_WIDTH: 5, + GLOBAL_NODE_HEIGHT: 5, + GLOBAL_NODE_MARGIN: 5, +}; + +if (typeof window !== 'undefined') { +window.NODE_DEFAULT_FILL = window.NODE_DEFAULT_FILL || 'white'; +window.NODE_DEFAULT_STROKE = window.NODE_DEFAULT_STROKE || 'black'; +window.NODE_DEFAULT_STROKE_WIDTH = window.NODE_DEFAULT_STROKE_WIDTH || '1'; +window.GLOBAL_LINK_STROKE = window.GLOBAL_LINK_STROKE || 'black'; +window.GLOBAL_LINK_STROKE_WIDTH = window.GLOBAL_LINK_STROKE_WIDTH || '1'; +window.TEXT_DEFAULT_COLOR = window.TEXT_DEFAULT_COLOR || 'black'; +} +export default globalConfig; diff --git a/src/libs/rc-spider/src/color/index.js b/src/libs/rc-spider/src/color/index.js new file mode 100644 index 000000000..a8c90b154 --- /dev/null +++ b/src/libs/rc-spider/src/color/index.js @@ -0,0 +1,9 @@ +import color from 'color'; + +class SpiderColor { + darken(colorString, alpha) { + return color(colorString).darken(alpha).hexString(); + } +} + +export default new SpiderColor(); diff --git a/src/libs/rc-spider/src/dataLoader/index.js b/src/libs/rc-spider/src/dataLoader/index.js new file mode 100644 index 000000000..26d2a3e54 --- /dev/null +++ b/src/libs/rc-spider/src/dataLoader/index.js @@ -0,0 +1,116 @@ +import { Iterable } from 'immutable'; +import Node from '../base/Node'; +/** + * loadArrayData + * @param data + * @returns {{nodes: *, links: *}} + */ +function loadArrayData(arr, spider) { + const nodeMap = {}; + const linkMap = {}; + // 把所有节点放置到map里 + arr.forEach(data => { + nodeMap[data.id] = new Node(data, spider); + }); + + arr.forEach(data => { + const currentNode = nodeMap[data.id]; + if (nodeMap[data.id] && nodeMap[data.parent]) { + const parentNode = nodeMap[data.parent]; + + const source = parentNode; + const target = currentNode; + const key = `${source.id}-${target.id}`; + linkMap[key] = { + source, target, + }; + parentNode.__outDegree += 1; + parentNode.children.push(currentNode); + currentNode.__inDegree += 1; + } + }); + return { + nodes: new Iterable(nodeMap), + links: new Iterable(linkMap), + }; +} +/** + * 加载图的数据 + * @param data + * @param spider + */ +function loadGraphData(data, spider) { + const nodeMap = {}; + const linkMap = {}; + data.nodes.map(rawNode => { + const node = new Node(rawNode, spider); + nodeMap[node.id] = node; + }); + data.links.map(rawLink => { + const key = `${rawLink.from}-${rawLink.to}`; + const source = nodeMap[rawLink.from]; + const target = nodeMap[rawLink.to]; + linkMap[key] = Object.assign({ + source, + target, + }, rawLink); + }); + return { + nodes: new Iterable(nodeMap), + links: new Iterable(linkMap), + }; +} +/** + * loadStructuralData + * 加载结构化的数据 + * @param data + * @returns {*} + */ +function loadStructuralData(data, spider) { + const nodeMap = {}; + const linkMap = {}; + const currentData = data; + + function readNode(nodeData, parent) { + const node = new Node(nodeData, spider); + + nodeMap[node.id] = node; + + if (parent) { + const source = parent; + const target = node; + const key = `${source.id}-${target.id}`; + linkMap[key] = { + source, target, + }; + parent.__outDegree += 1; + node.parent = parent; + node.__inDegree += 1; + } + + if (nodeData.children && nodeData.children.length) { + nodeData.children.forEach(child => { + readNode(child, nodeData); + }); + } + } + + readNode(currentData); + return { + nodes: new Iterable(nodeMap), + links: new Iterable(linkMap), + }; +} +/** + * dataLoader + * @param data + */ +export default function dataLoader(data, spider) { + if (Array.isArray(data)) { + return loadArrayData(data, spider); + } + if (typeof data === 'object' && (data.nodes && data.links)) { + return loadGraphData(data, spider); + } + return loadStructuralData(data, spider); +} diff --git a/src/libs/rc-spider/src/index.js b/src/libs/rc-spider/src/index.js new file mode 100644 index 000000000..bdfbbbc5c --- /dev/null +++ b/src/libs/rc-spider/src/index.js @@ -0,0 +1,3 @@ +// export this package's api +import Spider from './Spider'; +export default Spider; diff --git a/src/libs/rc-spider/src/layout/base.js b/src/libs/rc-spider/src/layout/base.js new file mode 100644 index 000000000..92a7c07d7 --- /dev/null +++ b/src/libs/rc-spider/src/layout/base.js @@ -0,0 +1,15 @@ +class Layout { + constructor() { + + } + size(sizeArray) { + this.size = sizeArray; + return this; + } + projection(projectionFunc) { + this.projectionFunc = projectionFunc; + return this; + } +} + +export default Layout; diff --git a/src/libs/rc-spider/src/layout/cluster.js b/src/libs/rc-spider/src/layout/cluster.js new file mode 100644 index 000000000..df34bd240 --- /dev/null +++ b/src/libs/rc-spider/src/layout/cluster.js @@ -0,0 +1,61 @@ +import { hierarchyVisitAfter, separation } from '../base/Util'; +import _ from 'lodash'; +import LayoutBase from './base'; + +function clusterX(children) { + return children.reduce((x, child) => x + child.x, 0) / children.length; +} + +function clusterY(children) { + return 1 + _.max(children.map(child => child.y)); +} + +function clusterLeft(node) { + const children = node.children; + return children && children.length ? clusterLeft(children[0]) : node; +} + +function clusterRight(node) { + const children = node.children; + return children && children.length ? clusterRight(children[children.length - 1]) : node; +} + +class Cluster extends LayoutBase { + data(root) { + let previousNode; + let x = 0; + const size = this.size; + const projectionFunc = this.projectionFunc; + + hierarchyVisitAfter(root, (node) => { + const children = node.children; + if (children && children.length) { + node.x = clusterX(children); + node.y = clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + + const left = clusterLeft(root); + const right = clusterRight(root); + const x0 = left.x - separation(left, right) / 2; + const x1 = right.x + separation(right, left) / 2; + hierarchyVisitAfter(root, (node) => { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + + // projection .. + if (projectionFunc) { + const projectioned = projectionFunc(node); + node.x = projectioned[0]; + node.y = projectioned[1]; + } + }); + return root; + } +} + +export default Cluster; diff --git a/src/libs/rc-spider/src/layout/index.js b/src/libs/rc-spider/src/layout/index.js new file mode 100644 index 000000000..c313c147c --- /dev/null +++ b/src/libs/rc-spider/src/layout/index.js @@ -0,0 +1,8 @@ +const layout = {}; + +['cluster', 'tree'].forEach(item => { + const LayoutClass = require(`./${item}`); + layout[item] = () => new LayoutClass(); +}); + +export default layout; diff --git a/src/libs/rc-spider/src/layout/tree.js b/src/libs/rc-spider/src/layout/tree.js new file mode 100644 index 000000000..801de4fce --- /dev/null +++ b/src/libs/rc-spider/src/layout/tree.js @@ -0,0 +1,157 @@ +import { hierarchyVisitAfter } from '../base/Util'; +import _ from 'lodash'; +import LayoutBase from './base'; + +class Tree extends LayoutBase { + constructor() { + super(); + this.levelIndexes = []; + this.maxDeep = 0; + this.minX = 0; + this.maxX = 0; + } + walkLevel(node, level = 0) { + if (this.levelIndexes.length < level + 1) { + this.levelIndexes.push([]); + } + + const indexes = this.levelIndexes[level]; + indexes.push(node); + if (!node.children || node.children.length === 0) { + node.__depth = 1; + } else { + node.children.forEach(child => this.walkLevel(child, level + 1)); + node.__depth = _.max(node.children.map(child => child.__depth)) + 1; + } + this.maxDeep = Math.max(node.__depth, this.maxDeep); + node.__left_bound = new Float32Array(node.__depth); + node.__right_bound = new Float32Array(node.__depth); + } + walkRelative() { + for (let level = this.levelIndexes.length - 1; level >= 0; level --) { + const nodes = this.levelIndexes[level]; + nodes.forEach(node => { + if (node.__depth === 1) { + node.__left_bound[0] = -1; + node.__right_bound[0] = 1; + } else { + this.move(node.children, node); + } + }); + } + } + + move(children, node) { + let activeNode = children[0]; + const firstNode = children[0]; + let mLevel; + let cLevel; + let leftBounds; + let rightBounds; + + const firstNodeLeftBound = firstNode.__left_bound; + const firstNodeRightBound = firstNode.__right_bound; + const len = children.length - 1; + + const _len = node.__depth - 1; + const left = new Float32Array(_len); + const right = new Float32Array(_len); + + let maxR; + let tmp; + + left.fill(0xfffffff0); + + firstNode.x = 0; + + for (let j = 0; j < firstNode.__depth; j++) { + right[j] = firstNodeRightBound[j]; + left[j] = firstNodeLeftBound[j]; + } + + mLevel = firstNode.__depth; + + for (let i = 0; i <= len; i++) { + activeNode = children[i]; + cLevel = mLevel > activeNode.__depth ? activeNode.__depth : mLevel; + mLevel = mLevel > activeNode.__depth ? mLevel : activeNode.__depth; + + leftBounds = activeNode.__left_bound; + rightBounds = activeNode.__right_bound; + maxR = 0; + + for (let j = 0; j < cLevel; j++) { + tmp = right[j] - leftBounds[j]; + if (maxR < tmp) { + maxR = tmp; + } + } + + activeNode.x = maxR; + + for (let j = 0; j < activeNode.__depth; j++) { + right[j] = maxR + rightBounds[j]; + tmp = maxR + leftBounds[j]; + if (tmp < left[j]) { + left[j] = tmp; + } + } + } + + const center = (children[len].x + children[0].x) / 2; + children.forEach(child => child.x -= center); + + const currentRightBounds = node.__right_bound; + const currentLeftBounds = node.__left_bound; + currentLeftBounds[0] = -1; + currentRightBounds[0] = 1; + for (let j = 1; j < node.__depth; j++) { + currentRightBounds[j] = right[j - 1] - center; + currentLeftBounds[j] = left[j - 1] - center; + } + } + + walkAbsolute(ele, px) { + const children = ele.children; + if (children && children.length) { + children.forEach(child => { + let x = child.x || 0; + x = x + px; + child.x = x; + this.minX = Math.min(this.minX, x); + this.maxX = Math.max(this.maxX, x); + if (child.children && child.children.length) { + this.walkAbsolute(child, x); + } + }); + } + } + + data(root) { + const size = this.size; + const projectionFunc = this.projectionFunc; + + root.x = 0; + root.y = 0; + + this.walkLevel(root); + this.walkRelative(); + this.walkAbsolute(root, 0); + + const x0 = this.minX - 1; + const x1 = this.maxX + 1; + hierarchyVisitAfter(root, (node) => { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (node.__level__ ? node.__level__ / this.maxDeep : 0) * size[1]; + + if (projectionFunc) { + const projectioned = projectionFunc(node); + node.x = projectioned[0]; + node.y = projectioned[1]; + } + }); + return root; + } +} + +export default Tree; diff --git a/src/libs/rc-spider/src/shapes/Circle.jsx b/src/libs/rc-spider/src/shapes/Circle.jsx new file mode 100644 index 000000000..3731b55a2 --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Circle.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import Shape from './Shape'; +import ArtCircle from 'react-art/Circle'; + +class Circle extends Shape { + render() { + const { radius, fill, stroke, strokeWidth, onClick } = this.props; + return (); + } +} + +export default Circle; diff --git a/src/libs/rc-spider/src/shapes/Link.jsx b/src/libs/rc-spider/src/shapes/Link.jsx new file mode 100644 index 000000000..93b057a4a --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Link.jsx @@ -0,0 +1,58 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import ReactART from 'react-art'; +const Group = ReactART.Group; +import Text from './Text'; +const Shape = ReactART.Shape; +const Transform = ReactART.Transform; +import { diagonal, broke } from '../base/Util'; + +class Link extends Component { + render() { + const { projection } = this.props; + + const { data, text, stroke, strokeWidth, offset, textOffset, rotate, arrow } = this.props; + const { source, target } = data; + // default theme style + const pathId = `link-path-${source.id}-${target.id}`; + const path = this.props.type === 'broke' + ? broke(data, projection, offset) + : diagonal(data, projection, offset); + const svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + svgPath.setAttribute('d', path.path); + const midPoint = svgPath.getPointAtLength(Math.ceil(svgPath.getTotalLength() / 2)); + midPoint.x += parseInt(textOffset[0], 10); + midPoint.y += parseInt(textOffset[1], 10); + svgPath.remove(); + const points = path.points; + const movePoint = points[points.length - 1]; + const lastPoint = points[points.length - 2]; + let alpha = Math.atan( + (movePoint[1] - lastPoint[1]) / (movePoint[0] - lastPoint[0]) + ) / Math.PI * 2; + alpha = isNaN(alpha) ? 0 : (alpha + 1) * (movePoint[0] > lastPoint[0] ? 90 : -90); + const transform = new Transform().translate(movePoint[0], movePoint[1]).rotate(alpha); + return ( + + {arrow ? : null} + + {text} + + ); + } +} + +Link.propTypes = { + projection: PropTypes.func, + data: PropTypes.object, + offset: PropTypes.array, + textOffset: PropTypes.array, + text: PropTypes.string, + stroke: PropTypes.string, + arrow: PropTypes.boolean, + strokeWidth: PropTypes.string, + type: PropTypes.string, +}; + +export default Link; diff --git a/src/libs/rc-spider/src/shapes/Node.jsx b/src/libs/rc-spider/src/shapes/Node.jsx new file mode 100644 index 000000000..2866351e3 --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Node.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import Shape from './Shape'; +import ReactART from 'react-art'; +const Group = ReactART.Group; +const Transform = ReactART.Transform; + +class Node extends Shape { + renderTreeNode(child, index) { + const props = this.props; + const cloneProps = { + key: child.props.key || index, + width: child.props.width || props.width, + height: child.props.height || props.height, + fill: child.props.fill || props.fill || window.NODE_DEFAULT_FILL, + stroke: child.props.stroke || props.stroke || window.NODE_DEFAULT_STROKE, + strokeWidth: child.props.strokeWidth || props.strokeWidth || window.NODE_DEFAULT_STROKE_WIDTH, + }; + if (child.type.name === 'Circle') { + cloneProps.radius = child.props.radius || Math.min(cloneProps.width, cloneProps.height); + } + if (child.type.name === 'Text') { + cloneProps.color = child.props.color || props.fill || window.TEXT_DEFAULT_COLOR; + } + + return React.cloneElement(child, cloneProps); + } + + nodeClick() { + if (this.props.onClick) { + this.props.onClick.call(this, this.props.data.__data); + } + } + render() { + const { children, offset } = this.props; + const groupTransform = new Transform(); + groupTransform.translate(offset[0], offset[1]); + return ( + {React.Children.map(children, this.renderTreeNode, this)} + ); + } +} + +Node.propTypes = { + width: PropTypes.any.isRequired, + height: PropTypes.any.isRequired, +}; + +export default Node; diff --git a/src/libs/rc-spider/src/shapes/Rect.jsx b/src/libs/rc-spider/src/shapes/Rect.jsx new file mode 100644 index 000000000..ed009d40a --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Rect.jsx @@ -0,0 +1,33 @@ +import React from 'react'; +import ReactART from 'react-art'; +import Rectangle from 'react-art/Rectangle'; +const Group = ReactART.Group; +const Transform = ReactART.Transform; +import Shape from './Shape'; + + +class Rect extends Shape { + render() { + const { offset, transform, width, height, color, radius, stroke, strokeWidth } = this.props; + const rectTransform = transform || new Transform(); + rectTransform.translate(offset[0], offset[1]); + return ( + + {this.props.children} + ); + } +} + +React.defaultProps = { + radius: 0, +}; + +export default Rect; diff --git a/src/libs/rc-spider/src/shapes/Shape.jsx b/src/libs/rc-spider/src/shapes/Shape.jsx new file mode 100755 index 000000000..1b88de3c4 --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Shape.jsx @@ -0,0 +1,20 @@ +import React from 'react'; + +class Shape extends React.Component { + constructor(props) { + super(props); + } + + render() { + + } +} + +Shape.defaultProps = { + offset: [0, 0], + stroke: null, + strokeWidth: 1, +}; + + +export default Shape; diff --git a/src/libs/rc-spider/src/shapes/Text.jsx b/src/libs/rc-spider/src/shapes/Text.jsx new file mode 100644 index 000000000..8f86054e1 --- /dev/null +++ b/src/libs/rc-spider/src/shapes/Text.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import Shape from './Shape'; +import ReactART from 'react-art'; +const Transform = ReactART.Transform; +const ArtText = ReactART.Text; + +class Text extends Shape { + render() { + const { offset, children, color, transform, rotate, alignment, size } = this.props; + + const textTransform = transform || new Transform(); + textTransform.translate(offset[0], offset[1]); + rotate && textTransform.rotate(rotate); + return ( + {children} + ); + } +} + +Text.defaultProps = { + offset: [0, 0], +}; +export default Text; diff --git a/src/libs/rc-spider/src/shapes/index.jsx b/src/libs/rc-spider/src/shapes/index.jsx new file mode 100755 index 000000000..d939defdb --- /dev/null +++ b/src/libs/rc-spider/src/shapes/index.jsx @@ -0,0 +1,13 @@ +import Link from './Link'; +import Node from './Node'; +import Circle from './Circle'; +import Text from './Text'; +import Rect from './Rect'; + +export default { + Link, + Node, + Circle, + Rect, + Text, +}; diff --git a/src/libs/rc-spider/src/theme/default.js b/src/libs/rc-spider/src/theme/default.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/libs/rc-spider/tests/index.js b/src/libs/rc-spider/tests/index.js new file mode 100644 index 000000000..7ada0c70a --- /dev/null +++ b/src/libs/rc-spider/tests/index.js @@ -0,0 +1,6 @@ +import expect from 'expect.js'; +describe('rc-spider', () => { + it('render works', () => { + expect(true).to.be(true); + }); +});