ABOUT ME

-

Today
Yesterday
Total
  • ์ƒํ™œ์ฝ”๋”ฉ ๋งˆ์ธ๋“œ๋งต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ cytoscape ์‚ฌ์šฉ๋ฒ•
    Project/Web 2023. 7. 13. 21:24
    ๋ฐ˜์‘ํ˜•

    ๐Ÿš€ ๋ฐœ๋‹จ

    ์ƒํ™œ์ฝ”๋”ฉ์— ์ ‘์†ํ•ด์„œ ์ˆ˜์—… ์†Œ๊ฐœ ์„น์…˜์œผ๋กœ ๊ฐ€๋ฉด ์ˆ˜์—…๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋งˆ์ธ๋“œ ๋งต์ด ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๊ฐœ์ธ์ ์œผ๋กœ ๊ณต๋ถ€ํ•œ ๊ฒƒ๋“ค์˜ ํ๋ฆ„์„ ์œ„์™€ ๊ฐ™์ด ์ •๋ฆฌํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค.
    ๊ทธ๋ž˜์„œ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ cytoscape๋ผ๋Š” ๊ฒƒ์„ ํ™•์ธ ํ›„ ์ด๋ฅผ ํ™œ์šฉํ•ด ๋น„์Šทํ•œ ์‚ฌ์ดํŠธ๋ฅผ ๊ฐœ๋ฐœ์„ ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

     

    ๊ทธ๋Ÿฌ๋‚˜ cytoscape ๊ด€๋ จํ•œ ๋ณ„๋„์˜ ํ•œ๊ธ€ ์ •๋ณด๊ฐ€ ์—†์–ด ์˜์–ด๋ฅผ ์ž˜ ๋ชปํ•˜๋Š” ์ €๋Š” ์ˆ˜๋งŽ์€ ์‚ฝ์งˆ์˜ ์‹œ๊ฐ„์„ ๊ฑฐ์ณ์•ผ ํ–ˆ๊ธฐ์— ๋‹ค๋ฅธ ๋ถ„๋“ค์€ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ข€ ๋” ํŽธํ•˜๊ฒŒ ์“ฐ์‹ค ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์•Œ๊ฒŒ ๋œ ๊ฒƒ๋“ค์„ ํ•œ๊ธ€๊ธฐ๋ก์œผ๋กœ ๋‚จ๊น๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค!

     

    ๐Ÿงต ์ดˆ๊ธฐ ์„ค์ •

    ํˆด์€ Visual Studio Code ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…๋“œ๋ฆฌ๊ณ  NPM์€ ์„ค์น˜๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
    ๋จผ์ € ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„์„ ์—ด์–ด์„œ

     

    npm init -y

     

    ๋กœ ์ดˆ๊ธฐํ™” ํ•œ ํ›„

     

    npm install @babel/core @babel/preset-env @babel/preset-react babel-loader clean-webpack-plugin css-loader html-loader file-loader html-webpack-plugin mini-css-extract-plugin webpack webpack-cli webpack-dev-server cytoscape

     

    ๋ฅผ ์ž…๋ ฅํ•ด ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์„ ์„ค์น˜ํ•ด ์ค๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ์—”

     

     

    ์œ„์™€ ๊ฐ™์ด ๊ฒฝ๋กœ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    index.html

     

    <!DOCTYPE html>
    <html lang="ko">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Take Knowledge's Study Map</title>
    </head>
    <body>
    <div id="cy"></div>
    </body>
    </html>
    view raw cytoscape_01.html hosted with โค by GitHub

    style.css

     

    html,body,#cy {
    width: 100%;
    height: 100%;
    }
    body {
    margin: 0;
    }
    view raw cytoscape_02.css hosted with โค by GitHub

    index.js

     

     

    import cytoscape from 'cytoscape';
    import './style.css';
    // webpack์œผ๋กœ ๋ฌถ์–ด์ค˜์•ผ ํ•˜๋‹ˆ cssํŒŒ์ผ์„ ์ง„์ž…์ ์ธ index.js ์— import ํ•ฉ๋‹ˆ๋‹ค
    // ์•„๋ž˜๋Š” ๊ณต์‹ ์‚ฌ์ดํŠธ์— ์˜ฌ๋ผ์™€ ์žˆ๋Š” ์˜ˆ์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค
    var cy = cytoscape({
    container: document.getElementById('cy'), // container to render in
    elements: [ // list of graph elements to start with
    { // node a
    "data": { "id": 'a' }
    },
    { // node b
    "data": { "id": 'b' }
    },
    { // edge ab
    "data": { "id": 'ab', "source": 'a', "target": 'b' }
    }
    ],
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(id)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'line-color': '#ccc',
    'target-arrow-color': '#ccc',
    'target-arrow-shape': 'triangle'
    }
    }
    ],
    layout: {
    name: 'grid',
    rows: 5
    }
    });
    view raw cytoscape_03.js hosted with โค by GitHub

    .babelrc

    // .babelrc
    {
        "presets": [
            "@babel/preset-env"
        ]
    }

    .gitignore

     

    node_modules

     

    package.json

     

    // ์„ค์น˜๊ฐ€ ๋˜์—ˆ๋‹ค๋ฉด ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ ์ด๋ฏธ ๋™์ผํ•˜๊ฒŒ ์ž…๋ ฅ๋˜์–ด ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.
    // scripts ๋ถ€๋ถ„๋งŒ ์ž˜ ์ ์–ด์ฃผ์„ธ์š”!
    {
    "name": "cytoscape_prj",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "build": "webpack",
    "start": "webpack serve"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
    "@babel/core": "^7.22.5",
    "@babel/preset-env": "^7.22.5",
    "@babel/preset-react": "^7.22.5",
    "babel-loader": "^9.1.2",
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.8.1",
    "cytoscape": "^3.25.0",
    "file-loader": "^6.2.0",
    "html-loader": "^4.2.0",
    "html-webpack-plugin": "^5.5.3",
    "mini-css-extract-plugin": "^2.7.6",
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
    }
    }
    view raw cytoscape_04.json hosted with โค by GitHub

    webpack.config.js

     

    const path = require("path");
    const HtmlWebPackPlugin = require("html-webpack-plugin");
    // html ํŒŒ์ผ ์ถ”์ถœ ํ”Œ๋Ÿฌ๊ทธ์ธ์ž…๋‹ˆ๋‹ค
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    // css ํŒŒ์ผ ์ถ”์ถœ ํ”Œ๋Ÿฌ๊ทธ์ธ์ž…๋‹ˆ๋‹ค
    const { CleanWebpackPlugin } = require("clean-webpack-plugin");
    // build ํด๋” ์ž๋™ ์ •๋ฆฌ๋ฅผ ์œ„ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ž…๋‹ˆ๋‹ค
    module.exports = {
    entry: "./src/index.js",
    output: {
    filename: "bundle.js",
    path: path.resolve(__dirname + "/build"),
    },
    devServer: {
    static: {
    directory: path.join(__dirname, "public"),
    },
    compress: true,
    port: 9000,
    // ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ž๋™ ์ ์šฉ์„ ์œ„ํ•œ ์„ค์ •์ž…๋‹ˆ๋‹ค
    },
    mode: "none",
    module: {
    rules: [
    {
    test: /\.(js|jsx)$/,
    exclude: "/node_modules",
    use: ["babel-loader"],
    },
    {
    test: /\.html$/,
    use: [
    {
    loader: "html-loader",
    options: { minimize: true },
    },
    ],
    },
    {
    test: /\.css$/,
    use: [MiniCssExtractPlugin.loader, "css-loader"],
    },
    ],
    // js, jsx, html, css ํŒŒ์ผ ๋ฒˆ๋“ค๋ง ๊ด€๋ จ ์„ค์ •์ž…๋‹ˆ๋‹ค
    },
    plugins: [
    new HtmlWebPackPlugin({
    template: "./public/index.html",
    filename: "index.html",
    }),
    new MiniCssExtractPlugin({
    filename: "style.css",
    }),
    new CleanWebpackPlugin(),
    // ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์ •๋“ค์ž…๋‹ˆ๋‹ค
    ],
    };
    view raw cytoscape_05.js hosted with โค by GitHub

    ์œ„์™€ ๊ฐ™์ด ์„ค์ •ํ•ด ์ค€ ๋‹ค์Œ

    npm run start

    ์œ„์˜ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•œ ํ›„ http://localhost:9000/ ๋กœ ์ ‘์†ํ•˜๋ฉด

     

     

    ์œ„์™€ ๊ฐ™์€ ํ™”๋ฉด์ด ์ถœ๋ ฅ๋˜๊ณ , ์ด๋Ÿฌ๋ฉด ์ด์ œ ์„ธํŒ…์€ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค.

    ๐Ÿ”ฅ cytoscape ํ™œ์šฉ๋ฒ•

    ๐Ÿน ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ

    cytoscape๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  ๋จผ์ € node์™€ edge๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    ๋จผ์ € ๊ฑฐ์ ์ด ๋˜๋Š” node๋Š”

     

    "data": {
      "id": 'id',
      "url": '๋งํฌ๊ฑธ๊ณ  ์‹ถ์€ ์ฃผ์†Œ(์˜ต์…˜)'
      "label": 'ํ‘œ์‹œํ•˜๊ณ  ์‹ถ์€ ๋‚ด์šฉ(์˜ต์…˜)'
    }

     

    ์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑํ•ด์ฃผ๋ฉด ๋˜๊ณ  ์—ฐ๊ฒฐ์„ ์ธ edge๋Š”

     

    "data": {
    	"id": 'id',
        "source": '์—ฐ๊ฒฐํ•  ๋…ธ๋“œ ์ค‘ ํ•˜์œ„์— ๋‘˜ node id',
        "target":'์—ฐ๊ฒฐํ•  ๋…ธ๋“œ ์ค‘ ์ƒ์œ„์— ๋‘˜ node id'
    }

    ํ˜•ํƒœ๋กœ ์ž…๋ ฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

     

    source์— ํ•˜์œ„์— ๋‘˜ node๋ฅผ, target์— ์ƒ์œ„์— ๋‘˜ node๋ฅผ ๋‘ฌ์•ผ ํ•œ๋‹ค๋Š” ๋ถ€๋ถ„์ด ์˜์•„ํ•˜์‹ค ํ…Œ์ง€๋งŒ(์ €๋Š” ์ด๊ฒŒ ์–ด์ƒ‰ํ–ˆ์Šต๋‹ˆ๋‹ค) ๊ทธ ์ด์œ ๋Š” ์ž ์‹œ ํ›„ 'depth์— ๋”ฐ๋ผ node์˜ ํฌ๊ธฐ๋ฅผ ๋‹ค๋ฅด๊ฒŒ' ์ฑ•ํ„ฐ์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๊ทธ ์™ธ์— ์ฃผ์˜ํ•  ์ ์€ id์— ๊ณต๋ฐฑ๊ณผ .์ด ํฌํ•จ๋˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค. ํฌํ•จํ•ด๋„ ๋‹น์žฅ ๋ Œ๋”๋ง์—” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด cytoscape๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜ ์ค‘ id๋กœ node๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์“ธ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋‹ˆ ํฌํ•จํ•˜์ง€ ๋ง™์‹œ๋‹ค.

     

    ์ด ์ ์„ ์ฃผ์˜ํ•ด์„œ node์™€ edge๋ฅผ ๊ตฌ์„ฑํ•œ ํ›„ ๋ฐฐ์—ด๋กœ cytoscape ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ elements ๋ถ€๋ถ„์— ์ž…๋ ฅํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ œ ํ•„์š”์— ๋”ฐ๋ผ ๊ตฌ์„ฑํ•˜๊ณ  ์ž…๋ ฅํ•œ ์†Œ์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    import cytoscape from 'cytoscape';
    import './style.css';
    // webpack์œผ๋กœ ๋ฌถ์–ด์ค˜์•ผ ํ•˜๋‹ˆ cssํŒŒ์ผ์„ ์ง„์ž…์ ์ธ index.js ์— import ํ•ฉ๋‹ˆ๋‹ค
    const data = [
    {
    "data": {
    "id": "PJ-mindMap",
    "url": "https://github.com/nomelancholy/js-project-driven-study-mind-map/projects/1?add_cards_query=is%3Aopen",
    "label": "Project Driven Study Map"
    }
    },
    {
    "data": {
    "id": "ISSUE-packageJson",
    "url": "https://www.google.co.kr/search?newwindow=1&safe=off&sxsrf=ACYBGNQPahfceN-IrrIMqFcBxt0bBJxcog%3A1577373548670&source=hp&ei=bM8EXp3aJoKpoASW2InwAg&q=no+such+file+or+directory%2C+open+%27C%3A%5Cdev%5Cworkspace%5Cjs-seomal-clone%5Cpackage.json%27&oq=no+such+file+or+directory%2C+open+%27C%3A%5Cdev%5Cworkspace%5Cjs-seomal-clone%5Cpackage.json%27&gs_l=psy-ab.3...7437.7437..8911...1.0..0.95.95.1......0....2j1..gws-wiz.pzIrSS2UT84&ved=0ahUKEwidwK2wztPmAhWCFIgKHRZsAi4Q4dUDCAY&uact=5",
    "label": "package.json ์—๋Ÿฌ"
    }
    },
    {
    "data": { "id": "PJ-mindMap->ISSUE-packageJson", "source": "ISSUE-packageJson", "target": "PJ-mindMap" }
    },
    {
    "data": {
    "id": "STUDY-npmInit",
    "url": "https://stackoverflow.com/questions/9484829/npm-cant-find-package-json",
    "label": "npm ํŒจํ‚ค์ง€ ์„ค์น˜ ์ˆœ์„œ ์ˆ™์ง€"
    }
    },
    {
    "data": { "id": "ISSUE-packageJson->STUDY-npmInit", "source": "STUDY-npmInit", "target": "ISSUE-packageJson" }
    },
    {
    "data": {
    "id": "ISSUE-outsideModule",
    "url": "https://www.google.co.kr/search?newwindow=1&safe=off&sxsrf=ACYBGNT3L0sknJfq3DO75H55Q5VQJODk-Q%3A1577373778729&ei=UtAEXvGVLMLh-AbOm7CYDA&q=Uncaught+SyntaxError%3A+Cannot+use+import+statement+outside+a+modul&oq=Uncaught+SyntaxError%3A+Cannot+use+import+statement+outside+a+modul&gs_l=psy-ab.3..35i39j0l2j0i203l7.513620.513620..514369...0.0..0.167.374.1j2......0....2j1..gws-wiz.gwgT-rwsfWw&ved=0ahUKEwjxhomez9PmAhXCMN4KHc4NDMMQ4dUDCAs&uact=5",
    "label": "script module ์—๋Ÿฌ"
    }
    },
    {
    "data": { "id": "PJ-mindmap->ISSUE-outsideModule", "source": "ISSUE-outsideModule", "target": "PJ-mindMap" }
    },
    {
    "data": {
    "id": "STUDY-scriptModule",
    "url": "https://velog.io/@takeknowledge/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AA%A8%EB%93%88-%ED%95%99%EC%8A%B5-%EB%82%B4%EC%9A%A9-%EC%9A%94%EC%95%BD-lwk4drjnni",
    "label": "js module ํ•™์Šต"
    }
    },
    {
    "data": { "id": "ISSUE-outsideModule->STUDY-scriptModule", "source": "STUDY-scriptModule", "target": "ISSUE-outsideModule" }
    },
    {
    "data": {
    "id": "STUDY-scriptPosition",
    "url": "https://velog.io/@takeknowledge/script-%ED%83%9C%EA%B7%B8%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%9C%84%EC%B9%98%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C%EC%9A%94",
    "label": "script ํƒœ๊ทธ ์œ„์น˜ ํ•™์Šต"
    }
    },
    {
    "data": { "id": "ISSUE-outsideModule->STUDY-scriptPosition", "source": "STUDY-scriptPosition", "target": "ISSUE-outsideModule" }
    },
    {
    "data": {
    "id": "ISSUE-localCORS",
    "url": "https://www.google.co.kr/search?newwindow=1&safe=off&sxsrf=ACYBGNSmKE1wN_fBQuRtT5pwz0hZ5JqldQ%3A1577374293889&ei=VdIEXtP7NY-lmAX82Z7oDg&q=Access+to+script+at+%27file%3A%2F%2F%2FC%3A%2Fdev%2Fworkspace%2Fjs-seomal-clone%2Fjs%2Fcyto.js%27+from+origin+%27null%27+has+been+blocked+by+CORS+policy%3A+Cross+origin+requests+are+only+supported+for+protocol+schemes%3A+http%2C+data%2C+chrome%2C+chrome-extension%2C+https.&oq=Access+to+script+at+%27file%3A%2F%2F%2FC%3A%2Fdev%2Fworkspace%2Fjs-seomal-clone%2Fjs%2Fcyto.js%27+from+origin+%27null%27+has+been+blocked+by+CORS+policy%3A+Cross+origin+requests+are+only+supported+for+protocol+schemes%3A+http%2C+data%2C+chrome%2C+chrome-extension%2C+https.&gs_l=psy-ab.3..35i39j0i20i263l2j0i203l7.516217.516217..516645...0.0..0.177.281.0j2......0....2j1..gws-wiz.JE3_EPpI5o4&ved=0ahUKEwiT-tuT0dPmAhWPEqYKHfysB-0Q4dUDCAs&uact=5",
    "label": "local ์‹คํ–‰์‹œ CORS ์—๋Ÿฌ"
    }
    },
    {
    "data": { "id": "PJ-mindmap->ISSUE-localCORS", "source": "ISSUE-localCORS", "target": "PJ-mindMap" }
    },
    {
    "data": {
    "id": "STUDY-localCORS",
    "url": "https://velog.io/@takeknowledge/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-CORS-policy-%EA%B4%80%EB%A0%A8-%EC%97%90%EB%9F%AC%EA%B0%80-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-3gk4gyhreu",
    "label": "CORS & SOP ํ•™์Šต"
    }
    },
    {
    "data": { "id": "ISSUE-localCORS->STUDY-localCORS", "source": "STUDY-localCORS", "target": "ISSUE-localCORS" }
    },
    {
    "data": {
    "id": "ISSUE-moduleImport",
    "url": "https://goenning.net/2017/07/21/how-to-avoid-relative-path-hell-javascript-typescript-projects/",
    "label": "module import ๊ฒฝ๋กœ ์—๋Ÿฌ"
    }
    },
    {
    "data": { "id": "PJ-mindmap->ISSUE-moduleImport", "source": "ISSUE-moduleImport", "target": "PJ-mindMap" }
    },
    {
    "data": {
    "id": "STUDY-webpackBuild",
    "url": "https://github.com/nomelancholy/webpack-build-practice",
    "label": "webpack build ์‹ค์Šต"
    }
    },
    {
    "data": { "id": "ISSUE-moduleImport->STUDY-webpackBuild", "source": "STUDY-webpackBuild", "target": "ISSUE-moduleImport" }
    },
    {
    "data": {
    "id": "STUDY-jsBrowser",
    "url": "https://github.com/nomelancholy/webpack-build-practice",
    "label": "js ์—”์ง„๊ณผ runtime ํ•™์Šต"
    }
    },
    {
    "data": { "id": "STUDY-webpackBuild->STUDY-jsBrowser", "source": "STUDY-jsBrowser", "target": "STUDY-webpackBuild" }
    }
    ];
    // ์•„๋ž˜๋Š” ๊ณต์‹ ์‚ฌ์ดํŠธ์— ์˜ฌ๋ผ์™€ ์žˆ๋Š” ์˜ˆ์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค
    const cy = cytoscape({
    container: document.getElementById('cy'), // container to render in
    elements: data,
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(id)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'line-color': '#ccc',
    'target-arrow-color': '#ccc',
    'target-arrow-shape': 'triangle'
    }
    }
    ],
    layout: {
    name: 'grid',
    rows: 5
    }
    });
    view raw cytoscape_06.js hosted with โค by GitHub

    ๊ทธ๋Ÿฌ๋‚˜ ์œ„์™€ ๊ฐ™์ด ์ž…๋ ฅํ•˜๋ฉด

     

    ๋ณด๋‹ค์‹œํ”ผ ํ™”๋ฉด์ด seomal.org์—์„œ ๋ณด๋˜ ๊ฒƒ๊ณผ๋Š” ๋งŽ์ด ๋‹ค๋ฅธ ํ™”๋ฉด์ด ๋‚˜์˜ต๋‹ˆ๋‹ค. ์ฐจ๊ทผ ์ฐจ๊ทผ ์ซ“์•„๊ฐ€ ๋ด…์‹œ๋‹ค.

    ๐Ÿ‘› id๊ฐ€ ์•„๋‹Œ ๋ผ๋ฒจ์ด ํ‘œ์‹œ๋˜๊ฒŒ

     

    ๋จผ์ € node ์œ„์— id๊ฐ€ ์•„๋‹Œ ์šฐ๋ฆฌ๊ฐ€ ์ž…๋ ฅํ•œ ๋ผ๋ฒจ์ด ํ‘œ์‹œ๋˜๋„๋ก ํ•ด๋ด…์‹œ๋‹ค. ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. index.js ํ•˜๋‹จ style ์ชฝ์—์„œ node์˜ style์„ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ณด๋ฉด label์ด data(id)๋กœ ๋˜์–ด ์žˆ๋Š”๋ฐ ์ด๊ฑธ data(label)๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด

     

    import cytoscape from 'cytoscape';
    import './style.css';
    const data = ...
    const cy = cytoscape({
    container: document.getElementById('cy'), // container to render in
    elements: data,
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    'label': 'data(label)'
    //
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'line-color': '#ccc',
    'target-arrow-color': '#ccc',
    'target-arrow-shape': 'triangle'
    }
    }
    ],
    layout: {
    name: 'grid',
    rows: 5
    }
    });
    view raw cytoscape_07.js hosted with โค by GitHub

     

    id๊ฐ€ ์•„๋‹Œ label์ด node์˜ ์ด๋ฆ„์œผ๋กœ ๋‚˜์˜ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๐Ÿ”€ edge styling

     

    ๋‹ค์Œ์œผ๋กœ๋Š” edge์˜ ์Šคํƒ€์ผ๋ง์„ ํ•ด๋ณด์ฃ . ๋จผ์ € edge์˜ ๋ฐฉํ–ฅ์„ ํ‘œ์‹œํ•ด๋ด…์‹œ๋‹ค. ์ด ์„ค์ •์€ style์—์„œ edge์˜ style์„ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์˜ ๊ฐ’์„ ํ†ตํ•ด ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๋จผ์ € ์„ธํŒ…๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ 'curve-style'์˜ ๊ฐ’์„ 'bezier'๋กœ ์ฃผ๋ฉด ํ™”์‚ดํ‘œ๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค.

     

    // index.js ์˜ style ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ „์ฒด ์ฝ”๋“œ๋Š” ๋งˆ์ง€๋ง‰์— ์˜ฌ๋ฆด๊ฒŒ์š”
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(label)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    // ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„
    'curve-style': 'bezier',
    //
    'line-color': '#ccc',
    'target-arrow-color': '#ccc',
    'target-arrow-shape': 'triangle'
    }
    }
    ],
    view raw cytoscape_08.js hosted with โค by GitHub

    ๊ทธ๋Ÿฐ๋ฐ ํ™”์‚ดํ‘œ ๋ฐฉํ–ฅ์ด ์ƒ์œ„๋ฅผ ๊ฐ€๋ฅดํ‚ค๊ณ  ์žˆ๋Š”๊ฒŒ ๋ญ”๊ฐ€ ์–ด์ƒ‰ํ•˜์ฃ ? ๊ณ ์ณ๋ด…์‹œ๋‹ค.
    target-arrow-shape์™€ target-arrow-color์—์„œ source-arrow-shape์™€ source-arrow-color๋กœ์š”.
    ๊ทธ๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ํ™”์‚ดํ‘œ ๋ฐฉํ–ฅ์ด ๋ฐ”๋€๋‹ˆ๋‹ค.

     

    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(label)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'curve-style': 'bezier',
    'line-color': '#ccc',
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    'source-arrow-color': '#ccc',
    'source-arrow-shape': 'triangle'
    //
    }
    }
    ],
    view raw cytoscape_09.js hosted with โค by GitHub

     

    ๋งˆ์ง€๋ง‰์œผ๋กœ ํ™”์‚ดํ‘œ ๋ชจ์–‘๋„ ๋ฐ”๊ฟ”๋ด…์‹œ๋‹ค. ํ™”์‚ดํ‘œ ๋ชจ์–‘์€ ์—ฌ๊ธฐ์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

     

    ์ „ vee๊ฐ€ ๋งˆ์Œ์— ๋“ค๋”๊ตฐ์š”. ์ ์šฉํ•˜๋ฉด

     

     

    ์ข€ ๋” ๋‚ ์นด๋กœ์šด ํ™”์‚ดํ‘œ ๋ชจ์–‘์œผ๋กœ ์ž˜ ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค.

     

    data ๋ถ€๋ถ„์„ ์ƒ๋žตํ•œ ์—ฌ๊ธฐ๊นŒ์ง€์˜ ์ „์ฒด ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    import cytoscape from 'cytoscape';
    import './style.css';
    const data = ...
    const cy = cytoscape({
    container: document.getElementById('cy'), // container to render in
    elements: data,
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(label)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'line-color': '#ccc',
    'source-arrow-color': '#ccc',
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    'source-arrow-shape': 'vee'
    //
    }
    }
    ],
    layout: {
    name: 'grid',
    rows: 5
    }
    });
    view raw cytoscape_10.js hosted with โค by GitHub

    ๐Ÿ“Ÿ layout ์„ค์ •

    ๋‹ค์Œ์œผ๋กœ๋Š” layout์„ ์„ค์ •ํ•ด์„œ ~์“ธ๋ฐ์—†์ด~ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ํ˜•ํƒœ๋ฅผ ์ข€ ๋” ๋งˆ์ธ๋“œ๋งต์Šค๋Ÿฝ๊ฒŒ ๋ฐ”๊ฟ”๋ด…์‹œ๋‹ค
    layout์˜ ํ˜•ํƒœ๋“ค์€ ์—ฌ๊ธฐ์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ „ cose-bilkent๊ฐ€ ๋งˆ์Œ์— ๋“œ๋„ค์š”. ์ด๊ฑธ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

     

    ๋จผ์ € ์„ค์น˜๋ฅผ ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„์„ ํ•˜๋‚˜ ๋” ์—ฌ์‹œ๊ณ 

     

    npm install cytoscape-cose-bilkent

     

    ์„ ์ž…๋ ฅํ•ด ํ•ด๋‹น layout์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„์—” index.js ์ตœ์ƒ๋‹จ์œผ๋กœ ์ด๋™ํ•ด์„œ

     

    import cytoscape from 'cytoscape';
    import coseBilkent from 'cytoscape-cose-bilkent';
    cytoscape.use(coseBilkent);
    import './style.css';
    ...
    ...
    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    'background-color': '#666',
    'label': 'data(label)'
    }
    },
    {
    selector: 'edge',
    style: {
    'width': 3,
    'curve-style': 'bezier',
    'line-color': '#ccc',
    'source-arrow-color': '#ccc',
    'source-arrow-shape': 'vee'
    }
    }
    ],
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    layout: {
    name: 'cose-bilkent',
    animate: false,
    gravityRangeCompound: 1.5,
    fit: true,
    tile: true
    }
    //
    view raw cytoscape_11.js hosted with โค by GitHub

     

    ์œ„์™€ ๊ฐ™์ด cytoscape-cose-bilkent๋ฅผ import ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋„๋ก ์„ ์–ธํ•œ ํ›„
    node์™€ edge์˜ style๊ด€๋ จ ์„ค์ •์„ ํ•ด์คฌ๋˜ ๋ถ€๋ถ„ ์•„๋ž˜ ์žˆ๋Š” layout์„ ๋ฐ”๊ฟ”์ฃผ๋ฉด

     

     

    ๋งˆ์นจ๋‚ด ๋งˆ์ธ๋“œ๋งต ๊ฐ™์€ ํ˜•ํƒœ๊ฐ€ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค!

     

    ๐Ÿงฒ ํ•˜์ดํผ ๋งํฌ ์—ฐ๊ฒฐ

     

    ์ด์ œ node๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ๋•Œ ์ž…๋ ฅํ•ด์ค€ url์ด ์ƒˆ์ฐฝ์—์„œ ์—ด๋ฆฌ๊ฒŒ ์„ค์ •ํ•ด ์ค์‹œ๋‹ค.

    cytoscape์—๋Š” on() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    const cy = cytoscape({ ... });
    cy.on('tap', function (e) {
    const url = e.target.data('url')
    if (url && url !== '') {
    window.open(url);
    }
    });
    view raw cytoscape_12.js hosted with โค by GitHub

     

    tap์„ ์ธ์ž๋กœ ์ค˜์„œ ํด๋ฆญ์ด๋ฒคํŠธ๋ฅผ ์ฃผ๊ณ  ํ•ด๋‹น url์ด ์ƒˆ์ฐฝ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๊ฒŒ ์„ค์ •ํ•ด์ฃผ๋ฉด

     

     

    ํด๋ฆญ์‹œ ๋งํฌ๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

     

    ๐Ÿ”Š depth์— ๋”ฐ๋ผ node์˜ ํฌ๊ธฐ๋ฅผ ๋‹ค๋ฅด๊ฒŒ

     

    ์ด์ œ depth์— ๋”ฐ๋ผ node์˜ ํฌ๊ธฐ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค.
    ๋จผ์ € ์ด๊ฑธ ์œ„ํ•ด์„  ๋™์ผํ•œ data๋ฅผ elements๋กœ ๊ฐ–๋Š” cytoscape ๊ฐ์ฒด๊ฐ€ ํ•˜๋‚˜ ๋” ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    data์™€ cy ์‚ฌ์ด์— ํฌ๊ธฐ ๋ณ€๊ฒฝ์„ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , cy์˜style๋ถ€๋ถ„์— ๊ฐ€์„œ  width, height, font-size๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด

     

     

    const data = [...];
    const cy_for_rank = cytoscape({
    elements: data
    });
    // rank๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด data๋งŒ ์ž…๋ ฅํ•œ cytoscape ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค
    const pageRank = cy_for_rank.elements().pageRank();
    // elements๋“ค์˜ rank๋“ค์ž…๋‹ˆ๋‹ค.
    const nodeMaxSize = 50;
    const nodeMinSize = 5;
    const fontMaxSize = 8;
    const fontMinSize = 5;
    // ์ถ”ํ›„ ๋งˆ์šฐ์Šค ์ธ/์•„์›ƒ ์‹œ์—๋„ ํ™œ์šฉํ•ด์•ผ ํ•˜๋‹ˆ node์™€ font์˜ ์ตœ๋Œ€๊ฐ’/์ตœ์†Œ๊ฐ’์€ ๋ณ€์ˆ˜๋กœ ๋นผ์ค๋‹ˆ๋‹ค
    const cy = cytoscape({
    container: document.getElementById("cy"), // container to render in
    elements: data,
    style: [
    // the stylesheet for the graph
    {
    selector: "node",
    style: {
    "background-color": "#666",
    label: "data(label)",
    width: function (ele) {
    return nodeMaxSize * pageRank.rank("#" + ele.id()) + nodeMinSize;
    },
    height: function (ele) {
    return nodeMaxSize * pageRank.rank("#" + ele.id()) + nodeMinSize;
    },
    "font-size": function (ele) {
    return fontMaxSize * pageRank.rank("#" + ele.id()) + fontMinSize;
    },
    },
    },
    ],
    layout: {
    name: "cose-bilkent",
    animate: false,
    gravityRangeCompound: 1.5,
    fit: true,
    tile: true,
    },
    });
    ...
    view raw cytoscape_13.js hosted with โค by GitHub

     

     

    ๋งˆ์นจ๋‚ด depth์— ๋”ฐ๋ผ ํฌ๊ธฐ๊ฐ€ ์ฐจ๋“ฑ ์ ์šฉ๋˜๋Š” ๋ถ€๋ถ„๊นŒ์ง€๋„ ๊ตฌํ˜„์ด ๋๋‚ฌ์Šต๋‹ˆ๋‹ค.

     

    ๋”๋ณด๊ธฐ

    ์œ„์—์„œ๋„ ์ ์—ˆ์ง€๋งŒ ๋งŒ์•ฝ node id์— ๊ณต๋ฐฑ์ด๋‚˜ . ์ด ๋“ค์–ด๊ฐ€ ์žˆ์œผ๋ฉด ์ด ๋ถ€๋ถ„์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

     

    target์œผ๋กœ depth๊ฐ€ ๊นŠ์„ ์ˆ˜๋ก rank ๊ฐ’์ด ๋†’๊ฒŒ ์ ์šฉ๋˜๋”๊ตฐ์š”.
    ์œ„์—์„œ source์™€ target์„ ๊ฑฐ๊พธ๋กœ ์ ์€ ์ด์œ ๊ฐ€ ์ด rank ๊ฐ’ ๋งŒํผ node์˜ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค

     

    โœจ ๋งˆ์šฐ์Šค ์ธ / ์•„์›ƒ์‹œ ํ•˜์ด๋ผ์ดํŠธ ์ ์šฉ / ํ•ด์ œ

     

    ์ด์ œ ๋งˆ์šฐ์Šค ์ธ / ์•„์›ƒ์‹œ ํ•˜์ด๋ผ์ดํŠธ ์ ์šฉ / ํ•ด์ œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค.
    ๋งˆ์šฐ์Šค ์ธ/์•„์›ƒ ๊ฐ์ง€ ๋‘˜ ๋ชจ๋‘ ํด๋ฆญ์‹œ ํ•˜์ดํผ๋งํฌ ์—ฐ๊ฒฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„๋•Œ ์‚ฌ์šฉํ•œ on ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

     

    ...
    cy.on('tap', function (e) {...});
    cy.on('tapstart mouseover', 'node', function(e){
    console.log("in");
    });
    cy.on('tapend mouseout', 'node', function(e){
    console.log("out");
    });
    view raw cytoscape_14.js hosted with โค by GitHub

    ๋จผ์ € ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด ์ž˜ ๊ฐ์ง€ํ•˜๋Š”์ง€ ํ™•์ธํ•ด์ค์‹œ๋‹ค.
    ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋ฉด ๋‹ค์Œ์€ node์™€ edge์˜ style์„ ๋ฐ”๊ฟ”์ค„ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ์ฐจ๋ก€ํ•ฉ๋‹ˆ๋‹ค.

     

    ๋จผ์ € ์‚ฌ์šฉํ•  ์ƒ‰๊ณผ ํฌ๊ธฐ๊ฐ’๋“ค์„ ๋ณ€์ˆ˜๋กœ ๊บผ๋ƒ…์‹œ๋‹ค. ์ƒ‰์€ ์ „ ์—ฌ๊ธฐ์„œ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ node์˜ ํฌ๊ธฐ์™€ ์ƒ‰, font ํฌ๊ธฐ, edge & ํ™”์‚ดํ‘œ ํฌ๊ธฐ์™€ ์ƒ‰ ๋“ฑ๋“ฑ์„ ์„ค์ •ํ•ด

     

    const pageRank = cy_for_rank.elements().pageRank();
    // elements๋“ค์˜ rank๋“ค์ž…๋‹ˆ๋‹ค.
    /// ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    const nodeMaxSize = 50;
    const nodeMinSize = 5;
    const nodeActiveSize = 28;
    const fontMaxSize = 8;
    const fontMinSize = 5;
    const fontActiveSize = 7;
    // node & font ํฌ๊ธฐ ๊ฐ’
    const edgeWidth = '2px';
    var edgeActiveWidth = '4px';
    const arrowScale = 0.8;
    const arrowActiveScale = 1.2;
    // edge & arrow ํฌ๊ธฐ๊ฐ’
    const dimColor = '#dfe4ea';
    const edgeColor = '#ced6e0';
    const nodeColor = '#57606f';
    const nodeActiveColor = '#ffa502';
    const successorColor = '#ff6348';
    // ์ƒ์œ„ node & edge color
    const predecessorsColor = '#1e90ff';
    // ํ•˜์œ„ node & edge color
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    const cy = cytoscape({...});
    view raw cytoscape_15.js hosted with โค by GitHub

    ์œ„์˜ ์œ„์น˜์— ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ณ€์ˆ˜๋กœ ๋นผ๋ƒˆ์œผ๋‹ˆ ํ•˜๋“œ์ฝ”๋”ฉ ๋˜์–ด ์žˆ๋˜ style ๊ฐ’๋„ ๋ณ€๊ฒฝ์„ ํ•ด์ค˜์•ผ๊ฒ ์ฃ 

     

    style: [ // the stylesheet for the graph
    {
    selector: 'node',
    style: {
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    'background-color': nodeColor,
    //
    'label': 'data(label)',
    'width': function (ele) {
    return nodeMaxSize * pageRank.rank('#' + ele.id()) + nodeMinSize;
    },
    'height': function (ele) {
    return nodeMaxSize * pageRank.rank('#' + ele.id()) + nodeMinSize;
    },
    'font-size': function (ele) {
    return fontMaxSize * pageRank.rank('#' + ele.id()) + fontMinSize;
    },
    // ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„
    'color': nodeColor
    //
    }
    },
    {
    selector: 'edge',
    style: {
    // ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„
    'width': edgeWidth,
    'curve-style': 'bezier',
    'line-color': edgeColor,
    'source-arrow-color': edgeColor,
    'source-arrow-shape': 'vee',
    'arrow-scale': arrowScale
    //
    }
    }
    ],
    view raw cytoscape_17.js hosted with โค by GitHub

     

    ์œ„์™€ ๊ฐ™์ด ๋ฐ”๊ฟจ์œผ๋ฉด ์ด์ œ ์ด ๋„ค๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์ด๋ฆ„๊ณผ ์—ญํ• ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • setDimStyle(target_cy, style)
      ๋ชจ๋“  node์™€ edge๋ฅผ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • setFocus(target_element, successorColor, predecessorsColor, edgeWidth, arrowScale)
      ์„ ํƒํ•œ node ์™€ edge, ๊ทธ๋ฆฌ๊ณ  ์ƒํ•˜์œ„ node์™€ edge๋ฅผ ํฌ๊ธฐ์™€ ์ƒ‰์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • setOpacityElement(target_element, degree)
      opacity๋ฅผ ํ™œ์šฉํ•ด ๋ฐ”๋กœ ์ด์›ƒํ•œ ์—ฐ๊ด€๊ด€๊ณ„์™€ ๊ทธ๋ ‡์ง€ ์•Š์€ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • setResetFocus(target_cy)
      node๋ฅผ ์„ ํƒํ•˜๊ธฐ ์ „์˜ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

    ํ•จ์ˆ˜์˜ ์ƒ์„ธ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค

     

    function setDimStyle(target_cy, style) {
    target_cy.nodes().forEach(function (target) {
    target.style(style);
    });
    target_cy.edges().forEach(function (target) {
    target.style(style);
    });
    }
    function setFocus(target_element, successorColor, predecessorsColor, edgeWidth, arrowScale) {
    target_element.style('background-color', nodeActiveColor);
    target_element.style('color', nodeColor);
    target_element.successors().each(function (e) {
    // ์ƒ์œ„ ์—ฃ์ง€์™€ ๋…ธ๋“œ
    if (e.isEdge()) {
    e.style('width', edgeWidth);
    e.style('arrow-scale', arrowScale);
    }
    e.style('color', nodeColor);
    e.style('background-color', successorColor);
    e.style('line-color', successorColor);
    e.style('source-arrow-color', successorColor);
    setOpacityElement(e, 0.5);
    }
    );
    target_element.predecessors().each(function (e) {
    // ํ•˜์œ„ ์—ฃ์ง€์™€ ๋…ธ๋“œ
    if (e.isEdge()) {
    e.style('width', edgeWidth);
    e.style('arrow-scale', arrowScale);
    }
    e.style('color', nodeColor);
    e.style('background-color', predecessorsColor);
    e.style('line-color', predecessorsColor);
    e.style('source-arrow-color', predecessorsColor);
    setOpacityElement(e, 0.5);
    });
    target_element.neighborhood().each(function (e) {
    // ์ด์›ƒํ•œ ์—ฃ์ง€์™€ ๋…ธ๋“œ
    setOpacityElement(e, 1);
    }
    );
    target_element.style('width', Math.max(parseFloat(target_element.style('width')), nodeActiveSize));
    target_element.style('height', Math.max(parseFloat(target_element.style('height')), nodeActiveSize));
    target_element.style('font-size', Math.max(parseFloat(target_element.style('font-size')), fontActiveSize));
    }
    function setOpacityElement(target_element, degree) {
    target_element.style('opacity', degree);
    }
    function setResetFocus(target_cy) {
    target_cy.nodes().forEach(function (target) {
    target.style('background-color', nodeColor);
    var rank = pageRank.rank(target);
    target.style('width', nodeMaxSize * rank + nodeMinSize);
    target.style('height', nodeMaxSize * rank + nodeMinSize);
    target.style('font-size', fontMaxSize * rank + fontMinSize);
    target.style('color', nodeColor);
    target.style('opacity', 1);
    });
    target_cy.edges().forEach(function (target) {
    target.style('line-color', edgeColor);
    target.style('source-arrow-color', edgeColor);
    target.style('width', edgeWidth);
    target.style('arrow-scale', arrowScale);
    target.style('opacity', 1);
    });
    }
    view raw cytoscape_18.js hosted with โค by GitHub

    ์ด์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด์ฃผ์‹œ๊ณ , ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ์‚ฌ์šฉํ•ด์•ผ๊ฒ ์ฃ . ์•„๊นŒ ๋งŒ๋“ค์–ด ๋‘” mouse in๊ณผ out์„ ๊ฐ์ง€ํ•˜๋Š” ๋ถ€๋ถ„์—

     

    cy.on('tapstart mouseover', 'node', function (e) {
    setDimStyle(cy, {
    'background-color': dimColor,
    'line-color': dimColor,
    'source-arrow-color': dimColor,
    'color': dimColor
    });
    setFocus(e.target, successorColor, predecessorsColor, edgeActiveWidth, arrowActiveScale);
    });
    cy.on('tapend mouseout', 'node', function (e) {
    setResetFocus(e.cy);
    });
    view raw cytoscape_19.js hosted with โค by GitHub

    ์œ„์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ์„ธํŒ…ํ•ด์ค๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด

     

     

    ์ธ ์•„์›ƒ ์ด๋ฒคํŠธ๊ฐ€ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

     

    ๐ŸŒŒ ๋ธŒ๋ผ์šฐ์ € ํฌ๊ธฐ ๋ณ€๊ฒฝ์‹œ cytoscape ํฌ๊ธฐ ์กฐ์ •

     

    ์ด์ œ ๋ธŒ๋ผ์šฐ์ € ํฌ๊ธฐ ๋ณ€๊ฒฝ์‹œ cytoscape์˜ ํฌ๊ธฐ๊ฐ€ ์ž๋™์œผ๋กœ ์กฐ์ •๋˜๊ฒŒ ํ•ด๋ด…์‹œ๋‹ค. seomal.org์˜ ๊ฒฝ์šฐ

     

     

    ์œ„์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €์˜ ํฌ๊ธฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ cytoscape์˜ ํฌ๊ธฐ๊ฐ€ ์ž๋™์œผ๋กœ ๋ณ€ํ•˜์ง€๋งŒ

     

     

    ์šฐ๋ฆฐ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์—ด์–ด๋„ ์•„๋ฌด ๋ณ€ํ™”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค. ์ ์šฉ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

     

    cy.on('tapend mouseout', 'node', function (e) {...});
    // ์ถ”๊ฐ€๋˜๋Š” ๋ถ€๋ถ„
    let resizeTimer;
    window.addEventListener('resize', function () {
    this.clearTimeout(resizeTimer);
    resizeTimer = this.setTimeout(function(){
    cy.fit();
    },200);
    });
    //
    view raw cytoscape_20.js hosted with โค by GitHub

    ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด

     

     

    ๋ธŒ๋ผ์šฐ์ € ํฌ๊ธฐ ๋ณ€๊ฒฝ์‹œ cytoscape ํฌ๊ธฐ๊ฐ€ ์ž๋™์œผ๋กœ ์ž˜ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค!

     

    ๋”๋ณด๊ธฐ

    ์œ„ ์ฝ”๋“œ์—์„œ clearTimout๊ณผ setTimout ๋ถ€๋ถ„์„ ์ œ์™ธํ•˜๋ฉด resize ๊ฐ์ง€๋Š” ๋˜๋Š”๋ฐ cy.fit() ์‹คํ–‰์€ ์•ˆ๋˜๋”๊ตฐ์š”. ์ผ๋‹จ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•ด ํ•ด๊ฒฐ์€ ํ–ˆ๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ์ž‘๋™ํ•˜๋Š” ์ž์„ธํ•œ ์ด์œ ๋ฅผ ์•„๋Š” ๋ถ„ ํ˜น์‹œ ๊ณ„์‹œ๋ฉด ๋Œ“๊ธ€ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

     

    ๐Ÿ’ซ data ์ถ”์ถœ 

     

    ๊ธฐ๋Šฅ์€ ๋‹ค ๊ตฌํ˜„ํ–ˆ์œผ๋‹ˆ ์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ํŒŒ์ผ์„ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด data๋ฅผ ๋ณ„๋„์˜ json ํŒŒ์ผ๋กœ ์ถ”์ถœํ•ด๋ด…์‹œ๋‹ค.

     

     

    ์œ„์™€ ๊ฐ™์ด model ํด๋” ํ•˜์œ„์— data.json ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ 

    ๊ทธ ๋‹ค์Œ์€ webpack.config.js ํŒŒ์ผ๋กœ ๊ฐ€์„œ module - rules์—

     

    module: {
    rules: [
    {
    test: /\.(js|jsx)$/,
    exclude: "/node_modules",
    use: ["babel-loader"],
    },
    {
    test: /\.html$/,
    use: [
    {
    loader: "html-loader",
    options: { minimize: true },
    },
    ],
    },
    {
    test: /\.css$/,
    use: [MiniCssExtractPlugin.loader, "css-loader"],
    },
    {
    test: /\.json$/,
    type: "javascript/auto",
    loader: "file-loader",
    options: {
    name: "model/[name].[ext]",
    },
    include: [path.resolve(__dirname, "./model")],
    },
    ],
    },
    view raw cytoscape_21.js hosted with โค by GitHub

     

    ์œ„์ฒ˜๋Ÿผ json ๊ด€๋ จ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค. ์ดํ›„์—” index.js ์—์„œ data ๋ณ€์ˆ˜๋กœ ๋ฐ›๋˜ 

     

    const data = [...];

     

    [ ] ์„ ํฌํ•จํ•˜์—ฌ ๊ทธ ์•ˆ์— ์žˆ๋˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋“ค์„ ๋ณต์‚ฌํ•ด์„œ model - data.json์— ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•ด์ค๋‹ˆ๋‹ค.

     

    ...
    import '../model/data.json';
    fetch('./model/data.json', { mode: 'no-cors' })
    .then(function (res) {
    return res.json();
    })
    .then(function (data) {
    // ๊ธฐ์กด ์ฝ”๋“œ ์ด ์•ˆ์œผ๋กœ ๋ถ™์—ฌ๋„ฃ๊ธฐ!
    });
    view raw cytoscape_22.js hosted with โค by GitHub

    ์ดํ›„์—” index.js ์ƒ๋‹จ์— data.json ๊ฒฝ๋กœ๋ฅผ ์ž„ํฌํŠธ ํ•ด์ฃผ๊ณ  import ๋ถ€๋ถ„์„ ์ œ์™ธํ•œ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ data.json fetch ํ•จ์ˆ˜ ์•ˆ์œผ๋กœ ์ง‘์–ด๋„ฃ์œผ๋ฉด

     

     

     

     

     

    ํ™”๋ฉด์ด ์ž˜ ๋‚˜์˜ต๋‹ˆ๋‹ค! ์ดํ›„์—” gh pages๋‚˜ netlify๋ฅผ ํ™œ์šฉํ•ด ๋ฐฐํฌ ํ›„ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!

    ๐Ÿ‘ ๋งˆ์น˜๋ฉฐ

    ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ์ง„ํ–‰ ๊ณผ์ •์€ github project์— ์ •๋ฆฌํ•ด๋’€๊ณ  ์†Œ์Šค์ฝ”๋“œ๋Š” repository์— ์˜ฌ๋ ค๋’€์œผ๋‹ˆ
    ์„ค๋ช…์ด ๋ถ€์กฑํ–ˆ๋˜ ๋ถ€๋ถ„์€ ์ด ๋‘ ๊ณณ์„ ์ฐธ๊ณ ํ•ด์ฃผ์‹œ๊ณ  ์งˆ๋ฌธ์€ ๋Œ“๊ธ€์— ๋‚จ๊ฒจ์ฃผ์„ธ์š”!

     

    ๋ชจ์ชผ๋ก ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค!

    ๋ฐ˜์‘ํ˜•

    'Project > Web' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

    ๋Œ“๊ธ€

Designed by Tistory.