├── dev-app
├── .eslintignore
├── .gitignore
├── public
│ ├── favicon.png
│ ├── index.html
│ └── global.css
├── src
│ ├── main.js
│ ├── store.js
│ ├── components
│ │ ├── displays
│ │ │ ├── ProfilerDisplay.svelte
│ │ │ └── ComponentDisplay.svelte
│ │ ├── Hidden.svelte
│ │ ├── tree_hierarchy
│ │ │ ├── ComponentStats.svelte
│ │ │ └── ComponentTree.svelte
│ │ ├── Nav.svelte
│ │ └── profiler
│ │ │ └── ProfilerGraphs.svelte
│ ├── Nav.test.js
│ ├── utils
│ │ ├── exploreCompositeDataType.js
│ │ └── componentDisplayFuncs.js
│ └── App.svelte
├── .babelrc
├── .eslintrc.json
├── jest.config.js
├── package.json
└── rollup.config.js
├── icons
├── icon16.png
├── icon48.png
└── icon128.png
├── devtools.js
├── docs
├── images
│ ├── temp.png
│ ├── svelcro.png
│ └── svelcroEDIT.png
├── gifs
│ ├── installition.gif
│ ├── render-count.gif
│ ├── render-times.gif
│ └── component-tree-hierarchy.gif
└── LICENSE.md
├── background.html
├── devtools.html
├── background.js
├── manifest.json
├── panel.html
├── README.md
└── document_start.js
/dev-app/.eslintignore:
--------------------------------------------------------------------------------
1 | src/utils/componentDisplayFuncs.js
--------------------------------------------------------------------------------
/dev-app/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 |
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/icons/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/icons/icon16.png
--------------------------------------------------------------------------------
/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/icons/icon48.png
--------------------------------------------------------------------------------
/devtools.js:
--------------------------------------------------------------------------------
1 | chrome.devtools.panels.create('Svelcro', 'callback','panel.html')
2 |
3 |
4 |
--------------------------------------------------------------------------------
/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/icons/icon128.png
--------------------------------------------------------------------------------
/docs/images/temp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/images/temp.png
--------------------------------------------------------------------------------
/docs/images/svelcro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/images/svelcro.png
--------------------------------------------------------------------------------
/dev-app/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/dev-app/public/favicon.png
--------------------------------------------------------------------------------
/docs/gifs/installition.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/gifs/installition.gif
--------------------------------------------------------------------------------
/docs/gifs/render-count.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/gifs/render-count.gif
--------------------------------------------------------------------------------
/docs/gifs/render-times.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/gifs/render-times.gif
--------------------------------------------------------------------------------
/background.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/images/svelcroEDIT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/images/svelcroEDIT.png
--------------------------------------------------------------------------------
/docs/gifs/component-tree-hierarchy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/Svelcro/HEAD/docs/gifs/component-tree-hierarchy.gif
--------------------------------------------------------------------------------
/dev-app/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte';
2 |
3 | const app = new App({
4 | target: document.body,
5 | });
6 |
7 | export default app;
8 |
--------------------------------------------------------------------------------
/dev-app/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]],
3 | "plugins": ["babel-plugin-transform-vite-meta-env"],
4 | "ignore": ["/node_modules/"]
5 | }
6 |
--------------------------------------------------------------------------------
/dev-app/src/store.js:
--------------------------------------------------------------------------------
1 | import {writable, get} from 'svelte/store';
2 |
3 | export const compCountsStore = writable([]);
4 | export const compInstancesStore = writable({});
5 | export const compTimesStore = writable([]);
6 | export const compArrayStore = writable([]);
7 | export const type = writable('none');
8 |
--------------------------------------------------------------------------------
/dev-app/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": [
7 | "airbnb-base"
8 | ],
9 | "parserOptions": {
10 | "ecmaVersion": "latest",
11 | "sourceType": "module"
12 | },
13 | "rules": {
14 | "import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Sidebar
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/dev-app/src/components/displays/ProfilerDisplay.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
18 |
--------------------------------------------------------------------------------
/dev-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Svelte app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/dev-app/src/components/Hidden.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 | {#if shown}
21 |
22 | {/if}
--------------------------------------------------------------------------------
/dev-app/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | '^.+\\.js$': 'babel-jest',
4 | '^.+\\.svelte$': 'svelte-jester',
5 | '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub'
6 | },
7 | moduleFileExtensions: ['svelte', 'js'],
8 | moduleNameMapper: {
9 | d3: '/node_modules/d3/dist/d3.min.js',
10 | },
11 | testEnvironment: 'jsdom',
12 | setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
13 | testPathIgnorePatterns: ['./node_modules/'],
14 | };
15 |
--------------------------------------------------------------------------------
/dev-app/src/components/displays/ComponentDisplay.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
--------------------------------------------------------------------------------
/background.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | chrome.runtime.onInstalled.addListener(()=>{
4 | //right click Svelcro devtools context menu option
5 | chrome.contextMenus.create({
6 | "id" : "Svelcro",
7 | "title" : "Svelcro DevTools",
8 | "contexts" : ["all"]
9 | })
10 |
11 | chrome.runtime.onMessage.addListener((msg, sender, response)=> {
12 | // Recieves msg body from DEVTOOLSscripts
13 | if(msg){
14 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
15 | chrome.tabs.sendMessage(tabs[0].id, {header: msg}, function(response) {});
16 | });
17 | }
18 | return true;
19 | })
20 |
21 | })
--------------------------------------------------------------------------------
/dev-app/src/Nav.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/svelte';
2 | import nav from './components/nav.svelte';
3 |
4 | describe('Nav component tests: ', () => {
5 | it('Navbar is mounted when nav component is rendered', () => {
6 | render(nav);
7 | const navBar = screen.queryByTestId('nav-bar');
8 | expect(navBar).toBeInTheDocument();
9 | });
10 |
11 | it('Component button is mounted when nav component is rendered', () => {
12 | render(nav);
13 | const compButton = screen.queryByTestId('comp-button');
14 | expect(compButton).toBeInTheDocument();
15 | });
16 |
17 | it('Profiler button is mounted when nav component is rendered', () => {
18 | render(nav);
19 | const profilerButton = screen.queryByTestId('profiler-button');
20 | expect(profilerButton).toBeInTheDocument();
21 | });
22 | })
23 |
--------------------------------------------------------------------------------
/dev-app/src/utils/exploreCompositeDataType.js:
--------------------------------------------------------------------------------
1 | const exploreCompositeDataType = (node) => {
2 | if (node.type === 'Literal') {
3 | return node.value;
4 | }
5 | if (node.type === 'ArrayExpression') {
6 | if (node.elements[0].type === 'Literal') {
7 | return node.elements;
8 | }
9 | const arr = [];
10 | for (let i = 0; i < node.elements.length; i += 1) {
11 | arr.push(exploreCompositeDataType(node.elements[i]));
12 | }
13 | return arr;
14 | }
15 | const obj = {};
16 | for (let i = 0; i < node.properties.length; i += 1) {
17 | if (node.properties[i].value.type === 'Literal') {
18 | obj[node.properties[i].key.name || node.properties[i].key.value] = node.properties[i].value.value;
19 | } else {
20 | obj[node.properties[i].key.name] = exploreCompositeDataType(node.properties[i].value);
21 | }
22 | }
23 | return obj;
24 | };
25 | export default exploreCompositeDataType;
26 |
--------------------------------------------------------------------------------
/dev-app/src/components/tree_hierarchy/ComponentStats.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | {#each $compArrayStore as comp}
10 | -
11 | {`${comp.$$.id}: ${JSON.stringify(comp.$$.ctx[0])}`}
12 |
13 | {/each}
14 |
15 |
16 |
17 |
43 |
--------------------------------------------------------------------------------
/docs/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Svelcro
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dev-app/public/global.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | /* TEXT COLOR */
9 | color: rgba(245, 245, 245, 0.543);
10 |
11 |
12 | margin: 0;
13 | box-sizing: border-box;
14 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
15 | }
16 |
17 | a {
18 | color: rgb(0,100,200);
19 | text-decoration: none;
20 | }
21 |
22 | a:hover {
23 | text-decoration: underline;
24 | }
25 |
26 | a:visited {
27 | color: rgb(0,80,160);
28 | }
29 |
30 | label {
31 | display: block;
32 | }
33 |
34 | input, button, select, textarea {
35 | font-family: inherit;
36 | font-size: inherit;
37 | -webkit-padding: 0.4em 0;
38 | padding: 0.4em;
39 | box-sizing: border-box;
40 | border: 1px solid #ccc;
41 | border-radius: 2px;
42 | }
43 |
44 | input:disabled {
45 | color: #ccc;
46 | }
47 |
48 | button {
49 | color: #333;
50 | background-color: #f4f4f4;
51 | outline: none;
52 | }
53 |
54 | button:disabled {
55 | color: #999;
56 | }
57 |
58 | button:not(:disabled):active {
59 | background-color: #ddd;
60 | }
61 |
62 | button:focus {
63 | border-color: #666;
64 | }
65 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Svelcro",
3 | "version": "1.0",
4 | "minimum_chrome_version": "10.0",
5 | "manifest_version": 3,
6 | "devtools_page": "devtools.html",
7 | "background": {
8 | "service_worker": "background.js"
9 | },
10 | "content_security_policy": {
11 | "extension pages": "script-src 'self' https://d3js.org/d3.v7.min.js; object-src 'self'"
12 | },
13 | "permissions": [
14 | "contextMenus",
15 | "tabs",
16 | "activeTab"
17 | ],
18 | "content_scripts": [{
19 | "matches": ["https://*/*", "http://*/*"],
20 | "js": ["document_start.js"],
21 | "run_at": "document_start"
22 | }],
23 | "web_accessible_resources": [{
24 | "resources": ["contentScript.js"],
25 | "matches": ["https://*/*", "http://*/*"]
26 | },
27 | {
28 | "resources": ["document_start.js"],
29 | "matches": ["https://*/*", "http://*/*"]
30 | }],
31 | "externally_connectable": {
32 | "matches": ["http://localhost/*"]
33 | },
34 | "icons": { "16": "/icons/icon16.png",
35 | "48": "/icons/icon48.png",
36 | "128": "/icons/icon128.png" }
37 | }
38 |
--------------------------------------------------------------------------------
/dev-app/src/components/tree_hierarchy/ComponentTree.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
24 |
25 |
26 |
27 |
57 |
--------------------------------------------------------------------------------
/dev-app/src/components/Nav.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
31 |
32 | (child.shown = e.detail)}>
33 |
34 |
35 |
36 | (child1.shown = e.detail)}>
37 |
38 |
39 |
40 |
57 |
--------------------------------------------------------------------------------
/dev-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-app",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "rollup -c",
7 | "dev": "rollup -c -w",
8 | "start": "sirv public --no-clear",
9 | "test": "npx jest",
10 | "test:watch": "npm run test -- --watch"
11 |
12 | },
13 | "moduleFileExtensions": [
14 | "js",
15 | "svelte"
16 | ],
17 | "devDependencies": {
18 | "@babel/core": "^7.17.9",
19 | "@babel/preset-env": "^7.16.11",
20 | "@rollup/plugin-commonjs": "^17.0.0",
21 | "@rollup/plugin-node-resolve": "^11.0.0",
22 | "@testing-library/jest-dom": "^5.16.4",
23 | "@testing-library/svelte": "^3.1.1",
24 | "@testing-library/user-event": "^14.1.1",
25 | "babel-jest": "^22.4.4",
26 | "babel-plugin-transform-vite-meta-env": "^1.0.3",
27 | "eslint": "^8.14.0",
28 | "eslint-config-airbnb-base": "^15.0.0",
29 | "eslint-plugin-import": "^2.26.0",
30 | "jest": "^26.6.3",
31 | "jest-transform-stub": "^2.0.0",
32 | "rollup": "^2.3.4",
33 | "rollup-plugin-css-only": "^3.1.0",
34 | "rollup-plugin-livereload": "^2.0.0",
35 | "rollup-plugin-svelte": "^7.0.0",
36 | "rollup-plugin-terser": "^7.0.0",
37 | "sinon-chrome": "^3.0.1",
38 | "svelte": "^3.20.1",
39 | "svelte-jester": "^1.8.2",
40 | "svelte-preprocess": "^4.10.5"
41 | },
42 | "dependencies": {
43 | "cross-env": "^7.0.3",
44 | "d3": "^7.4.4",
45 | "jest-esm-transformer": "^1.0.0",
46 | "sirv-cli": "^2.0.0",
47 | "svelte-compiler": "^1.0.1",
48 | "svelte-preprocess": "^4.10.5",
49 | "svelte-spa-router": "^3.2.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/panel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Svelcro
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/dev-app/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import resolve from '@rollup/plugin-node-resolve';
4 | import livereload from 'rollup-plugin-livereload';
5 | import { terser } from 'rollup-plugin-terser';
6 | import css from 'rollup-plugin-css-only';
7 |
8 | const production = !process.env.ROLLUP_WATCH;
9 |
10 | function serve() {
11 | let server;
12 |
13 | function toExit() {
14 | if (server) server.kill(0);
15 | }
16 |
17 | return {
18 | writeBundle() {
19 | if (server) return;
20 | server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
21 | stdio: ['ignore', 'inherit', 'inherit'],
22 | shell: true
23 | });
24 |
25 | process.on('SIGTERM', toExit);
26 | process.on('exit', toExit);
27 | }
28 | };
29 | }
30 |
31 | export default {
32 | input: 'src/main.js',
33 | output: {
34 | sourcemap: true,
35 | format: 'iife',
36 | name: 'app',
37 | file: 'public/build/bundle.js'
38 | },
39 | plugins: [
40 | svelte({
41 | compilerOptions: {
42 | // enable run-time checks when not in production
43 | dev: !production
44 | }
45 | }),
46 | // we'll extract any component CSS out into
47 | // a separate file - better for performance
48 | css({ output: 'bundle.css' }),
49 |
50 | // If you have external dependencies installed from
51 | // npm, you'll most likely need these plugins. In
52 | // some cases you'll need additional configuration -
53 | // consult the documentation for details:
54 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
55 | resolve({
56 | browser: true,
57 | dedupe: ['svelte']
58 | }),
59 | commonjs(),
60 |
61 | // In dev mode, call `npm run start` once
62 | // the bundle has been generated
63 | !production && serve(),
64 |
65 | // Watch the `public` directory and refresh the
66 | // browser on changes when not in production
67 | !production && livereload('public'),
68 |
69 | // If we're building for production (npm run build
70 | // instead of npm run dev), minify
71 | production && terser()
72 | ],
73 | watch: {
74 | clearScreen: false
75 | }
76 | };
77 |
--------------------------------------------------------------------------------
/dev-app/src/App.svelte:
--------------------------------------------------------------------------------
1 |
67 |
68 |
69 | Svelcro
70 |
71 |
72 |
73 |
96 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [](https://github.com/oslabs-beta/Svelcro/pulls)
7 | []()
8 |
9 |
10 |
11 | The first component performance tracker for Svelte applications.
12 |
13 | # Features
14 |
15 | - Component Dependency Tree - View your components as a dependency tree or hierarchy.
16 | 
17 | - Component Stats - List state and properties in your components.
18 | - Profiler
19 | - Render Performance - Monitors component render time from start to finish.
20 | 
21 | - Render Count - Tracks how many times your components have rendered.
22 | 
23 |
24 | # Installation
25 |
26 | Extension Coming To Chrome Store Soon...
27 |
28 | Feel free to fork and clone this repo! Otherwise, just download Svelcro and save it somewhere on your computer.
29 |
30 | Make Svelcro/dev-app your current directory, install depencencies, and run build.
31 |
32 | ```
33 | cd Svelcro/dev-app
34 | npm install
35 | npm run build
36 | ```
37 |
38 | 
39 |
40 | Navigate to Chrome's extensions page at `chrome://extensions/`.
41 |
42 | Turn on 'developer mode' in the top-right corner of the page.
43 |
44 | Click on 'load unpacked' at the top-left, and select your local copy of the Svelcro directory.
45 |
46 | Open up your Chrome DevTools, and check to make sure Svelcro is available in the dropdown menu of the navbar!
47 |
48 | # How To Use
49 |
50 | Make sure your svelte application is in development mode.
51 |
52 | You can then open up Chrome DevTools and navigate to Svelcro.
53 |
54 | Visualize component dependencies and their respective state in the "Components" tab or monitor your component render performance in the "Profiler" tab.
55 |
56 | # Troubleshooting
57 |
58 | - Have you installed your Svelcro dependencies?
59 | - Sometimes it helps to refresh your webpage or Svelcro in the Chrome extensions page.
60 |
61 | # What's to come
62 |
63 | - Monitor applications built with SvelteKit
64 | - Time Machine feature to track history of application state
65 |
66 | # Contribute
67 |
68 | We would love to hear from you!
69 |
70 | Svelcro is currently in beta. If you would like to contribute please contact the authors at svelcrodt@gmail.com.
71 |
72 | Notice any issues or bugs? Open an issue!
73 |
74 | # Learn More
75 |
76 |
77 |
78 | Visit the [Svelcro website!](https://www.svelcro.dev/
79 | )
80 |
81 |
82 |
83 | Read more at Medium - [Component Performance Monitoring with Selvro](https://medium.com/@svelcrodt/component-performance-monitoring-in-svelte-with-svelcro-d0bbe1d6aae0)
84 |
85 | # Contributors
86 |
87 | Sara Kivikas - [@skivikas](https://github.com/skivikas)
88 |
89 | Rankin Draa - [@rankind94](https://github.com/rankind94)
90 |
91 | Yanming Yu - [@jimmyjameswong](https://github.com/jimmyjameswong)
92 |
93 | Zachary Daniels - [@zackdaniels](https://github.com/zackdaniels)
94 |
95 | # License
96 |
97 | [MIT](./docs/LICENSE.md)
98 |
--------------------------------------------------------------------------------
/document_start.js:
--------------------------------------------------------------------------------
1 | let editorExtensionId = chrome.runtime.id;
2 |
3 | const code = `let editorExtensionId = '${editorExtensionId}';
4 |
5 | (function () {
6 | 'use strict';
7 |
8 | const components = [];
9 |
10 | // object to hold render counts by component
11 | let nextId = 1;
12 |
13 | // Proxy object that trigger function when property values are changed
14 | let compCounts = new Proxy({}, {
15 | set: function (target, key, value) {
16 | target[key] = value;
17 |
18 | chrome.runtime.sendMessage(editorExtensionId,
19 | { header: "UPDATE_RENDER",
20 | compCounts: JSON.stringify(compCounts),
21 | compInstance: JSON.stringify(compInstance),
22 | compTimes: JSON.stringify(compTimes),
23 | compArray: JSON.stringify(components)
24 | });
25 | return true;
26 | }
27 | });
28 | // Object to track instances of components
29 | const compInstance = new Proxy({}, {
30 | set: function (target, key, value) {
31 | target[key] = value;
32 |
33 | // Send render count records to dev Tools
34 | chrome.runtime.sendMessage(editorExtensionId,
35 | { header: "UPDATE_INSTANCE",
36 | compCounts: JSON.stringify(compCounts),
37 | compInstance: JSON.stringify(compInstance),
38 | compTimes: JSON.stringify(compTimes),
39 | compArray: JSON.stringify(components)
40 | });
41 |
42 | return true;
43 | }
44 | });
45 |
46 | let compTimes = new Proxy({}, {
47 | set: function (target, key, value) {
48 | target[key] = value;
49 |
50 | chrome.runtime.sendMessage(editorExtensionId,
51 | { header: "UPDATE_TIMES",
52 | compCounts: JSON.stringify(compCounts),
53 | compInstance: JSON.stringify(compInstance),
54 | compTimes: JSON.stringify(compTimes),
55 | compArray: JSON.stringify(components)
56 | });
57 | return true;
58 | }
59 | });
60 |
61 | // add all Svelte components to array
62 | let start;
63 | let first = true;
64 |
65 | window.document.addEventListener('SvelteRegisterComponent', (e) => {
66 |
67 | start = window.performance.now();
68 |
69 | let isFirstAfterUpdate = true;
70 |
71 | const { component, tagName } = e.detail;
72 |
73 | component.$$['tag_name'] = tagName;
74 | component.$$['id'] = tagName + nextId;
75 | nextId++;
76 | const curId = component.$$.id;
77 | compCounts[curId] = 1;
78 | components.push(e.detail.component)
79 |
80 | // capturing all instance of components
81 | if(!compInstance[tagName]){
82 | compInstance[tagName] = 1;
83 | } else {
84 | compInstance[tagName] += 1;
85 | }
86 |
87 | if (first) {
88 | component.$$.on_mount.push(() => {
89 | let rendertime = window.performance.now() - start;
90 | const curId = component.$$.id;
91 | compTimes[curId] = parseFloat(rendertime).toFixed(3);
92 | compCounts[curId] = 1;
93 | })
94 | }
95 |
96 | component.$$.before_update.push(() => {
97 | let time = window.performance.now()
98 | component.$$.before_update.time = time;
99 | });
100 |
101 | component.$$.on_destroy.push(() => {
102 | compInstance[tagName] -= 1;
103 | // For render count
104 | delete compCounts[curId];
105 | delete compTimes[curId];
106 | });
107 |
108 | component.$$.before_update.push(() => {
109 | let time = window.performance.now()
110 | component.$$.before_update.time = time;
111 | });
112 |
113 | component.$$.after_update.push(() => {
114 | let now = window.performance.now();
115 | const curId = component.$$.id;
116 | let rendertime = now - component.$$.before_update.time;
117 | if (isFirstAfterUpdate) { return isFirstAfterUpdate = false;}
118 |
119 | compCounts[curId] += 1;
120 | compTimes[curId] = parseFloat(rendertime).toFixed(3);
121 | });
122 |
123 | })
124 |
125 | window.addEventListener("message", function(event) {
126 | chrome.runtime.sendMessage(editorExtensionId,
127 | { header: "INITIAL_LOAD", compCounts: JSON.stringify(compCounts), compInstance: JSON.stringify(compInstance), compTimes: JSON.stringify(compTimes), compArray: JSON.stringify(components) });
128 | }, false);
129 |
130 | })();`
131 |
132 | document.documentElement.setAttribute('onreset', code);
133 | document.documentElement.dispatchEvent(new CustomEvent('reset'));
134 |
135 |
136 | chrome.runtime.onMessage.addListener((msg, sender, response)=> {
137 | window.postMessage({header : "APP MOUNTED"});
138 | return true;
139 | })
140 |
141 |
--------------------------------------------------------------------------------
/dev-app/src/components/profiler/ProfilerGraphs.svelte:
--------------------------------------------------------------------------------
1 |
214 |
215 |
216 |
230 |
231 |
232 |
233 |
300 |
--------------------------------------------------------------------------------
/dev-app/src/utils/componentDisplayFuncs.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { parse, walk } from 'svelte/compiler';
3 | import * as d3 from 'd3';
4 | import exploreCompositeDataType from "./exploreCompositeDataType.js";
5 |
6 | export const getData = (tab , compRecord) => {
7 | if (tab !== 'chart' && tab !== 'tree') return;
8 | let i = 0;
9 | let componentNames = [];
10 | const D3PreTree = [];
11 | // This is a pre- or partial tree with known relationships among componenets/files that go only 1 layer deep (this is all we need to build the rest of the tree)
12 | const unorderedListOfNodes = [];
13 | let componentTree;
14 |
15 | const createNode = (ast) => {
16 | const node = {};
17 | const dependencies = {};
18 | const state = {};
19 | const props = {};
20 | const elementOfD3PreTree = {};
21 |
22 | ast.instance.content.body.forEach((el) => {
23 | // Find dependencies (via import statements) of current svelte component/file and store the dep in the node for said svelte component/file
24 | if (
25 | el.type === "ImportDeclaration" &&
26 | el.source.value.includes(".svelte")
27 | ) {
28 | const componentName = `<${el.source.value.slice(
29 | el.source.value.lastIndexOf("/") + 1,
30 | el.source.value.lastIndexOf(".")
31 | )} />`;
32 | dependencies[componentName] = {};
33 | }
34 | // Find props (via export statements) of current svelte component/file and store the props in the node for said svelte component/file
35 | else if (el.type === "ExportNamedDeclaration") {
36 | props[el.declaration.declarations[0].id.name] = null;
37 | }
38 | });
39 |
40 | node[componentNames[i]] = Object.keys(dependencies).length ? dependencies : {};
41 |
42 | Object.defineProperty(node[componentNames[i]], "Props", {
43 | value: props,
44 | configurable: true,
45 | writable: true,
46 | enumerable: false
47 | });
48 |
49 | walk(ast, {
50 | enter(ASTnode, parent, prop, index) {
51 | if (ASTnode.hasOwnProperty("declarations")) {
52 | // For variable declarations that either have not been initialized or have a value that is equal to "null"
53 | if (!ASTnode.declarations[0].init) {
54 | state[ASTnode.declarations[0].id.name] = ASTnode.declarations[0].init;
55 | }
56 | // For variable declarations that have a value that is a primitive data type or is a "Literal"
57 | else if (ASTnode.declarations[0].init.type === "Literal") {
58 | state[ASTnode.declarations[0].id.name] = ASTnode.declarations[0].init.value;
59 | }
60 | // For variable declarations that have a value that is a composite data type
61 | else if (
62 | ASTnode.declarations[0].init.type === "ObjectExpression" ||
63 | ASTnode.declarations[0].init.type === "ArrayExpression"
64 | ) {
65 | console.log("AST NODE IS:", ASTnode)
66 | state[ASTnode.declarations[0].id.name] = exploreCompositeDataType(ASTnode.declarations[0].init);
67 | }
68 |
69 | Object.defineProperty(node[componentNames[i]], "State", {
70 | value: state,
71 | configurable: true,
72 | writable: true,
73 | enumerable: false
74 | });
75 | }
76 | },
77 | });
78 |
79 | if (Object.keys(node).length) {
80 | unorderedListOfNodes.push(node);
81 |
82 | // For D3
83 | const temp = {};
84 | temp["State"] = state;
85 | temp["Props"] = props;
86 | elementOfD3PreTree[componentNames[i]] = temp;
87 | D3PreTree.push(elementOfD3PreTree);
88 | }
89 | }
90 |
91 | const createTree = (arr) => {
92 | for (let j = 0; j < arr.length; j += 1) {
93 | let success = 0;
94 |
95 | const searchTree = (
96 | tree,
97 | keyToSearchFor,
98 | valToSubstituteIfKeyIsFound
99 | ) => {
100 | for (const key in tree) {
101 | if (key === keyToSearchFor) {
102 | tree[key] = valToSubstituteIfKeyIsFound;
103 | arr.splice(j, 1);
104 | success += 1;
105 | return true;
106 | }
107 | if (
108 | Object.keys(tree[key]).length &&
109 | searchTree(
110 | tree[key],
111 | keyToSearchFor,
112 | valToSubstituteIfKeyIsFound
113 | )
114 | ) {
115 | return true;
116 | }
117 | }
118 | return false;
119 | }
120 |
121 | for (const key in arr[j]) {
122 | // If an unordered array node has keys that are not null (an object and therefore has dependencies)
123 | if (Object.keys(arr[j][key]).length > 0) {
124 | // testing top-most component (second level)
125 | for (const nestedKey in arr[j][key]) {
126 | for (const masterKey in componentTree) {
127 | if (nestedKey === masterKey) {
128 | arr[j][key][nestedKey] = componentTree[masterKey];
129 | componentTree = arr[j];
130 | arr.splice(j, 1);
131 | success += 1;
132 | }
133 | }
134 | }
135 | }
136 | }
137 |
138 | for (const key in arr[j]) {
139 | if (!success) {
140 | searchTree(componentTree, key, arr[j][key]);
141 | }
142 | }
143 | if (success) {
144 | j -= success;
145 | success = 0;
146 | }
147 | }
148 |
149 | if (arr.length !== 0) {
150 | createTree(arr);
151 | }
152 | }
153 |
154 | const filterTree = (compRecord, templateStructured) => {
155 | // comp record tag names
156 | const compRecordTagNames = {}
157 |
158 | compRecord.forEach((comp) => {
159 | const curTag = comp.$$.tag_name;
160 | if (compRecordTagNames.hasOwnProperty(curTag)) compRecordTagNames[curTag] += 1;
161 | else compRecordTagNames[curTag] = 1;
162 | })
163 | console.log('filterTree - compRecordTagNames: ', compRecordTagNames);
164 | // helper
165 | const helper = (struc) => {
166 | // if no children, return
167 | if (!struc.children) return;
168 | // start at beginning of template structured
169 | // check that children have a match in compRecord
170 | const curChildren = struc.children;
171 | struc.children = curChildren.filter((child) => {
172 | return compRecordTagNames.hasOwnProperty(child.id);
173 | });
174 | struc.children.forEach((child) => {
175 | helper(child);
176 | })
177 | // console.log("filterTreeHelper - children after filter: ", struc.children);
178 | }
179 | // call helper
180 | helper(templateStructured);
181 | console.log('filterTree - templateStructured after', templateStructured)
182 | // return template structured
183 | return templateStructured;
184 | }
185 |
186 | // Get resources of inspected program and generate views
187 | chrome.devtools.inspectedWindow.getResources(resources => {
188 | const arrSvelteFiles = resources.filter(file =>file.url.includes(".svelte"));
189 | console.log("arrSvelteFiles: ", arrSvelteFiles);
190 | componentNames = arrSvelteFiles.map(svelteFile => `<${svelteFile.url.slice(
191 | svelteFile.url.lastIndexOf("/") + 1,
192 | svelteFile.url.lastIndexOf(".")
193 | )} />`);
194 |
195 | arrSvelteFiles.forEach(svelteFile => {
196 | svelteFile.getContent(source => {
197 | if (source) {
198 | const ast = parse(source);
199 | createNode(ast);
200 |
201 | if (i === componentNames.length - 1) {
202 | componentTree = unorderedListOfNodes[0];
203 | unorderedListOfNodes.shift();
204 | createTree(unorderedListOfNodes);
205 | }
206 | i += 1;
207 | }
208 | });
209 | });
210 |
211 | // For D3 component tree
212 | let AST = [];
213 | let urls = [];
214 |
215 | // retrieves URLs from Svelte files and adds them to urls array
216 | // adds each Svelte file's contents to AST array
217 | for (let i = 0; i < arrSvelteFiles.length; i++) {
218 | urls.push(JSON.parse(JSON.stringify(arrSvelteFiles[i])));
219 | arrSvelteFiles[i].getContent(content => {
220 | AST.push(parse(content));
221 | });
222 | }
223 |
224 | /* ---- D3 ---- */
225 | // executes after svelte.parse is completed
226 | setTimeout(() => {
227 | // modified D3PreTree so that it fits for D3 stratify function
228 | const newD3Pre = [];
229 | for (let eachObj of D3PreTree) {
230 | let temp = {};
231 | let key = Object.keys(eachObj)[0];
232 | let value = Object.values(eachObj)[0];
233 | key = key.split("");
234 | key.shift();
235 | key.pop();
236 | key.pop();
237 | key.pop();
238 | key = key.join("");
239 | temp[key] = value;
240 | newD3Pre.push(temp);
241 | }
242 |
243 | // declare object to assemble component template
244 | let bigData = {};
245 |
246 | // map out AST array so that it is easier to access the node that contains import declaration
247 | // iterated through the AST array and modified the source key to later match with url array to
248 | // combined into bigData object
249 | AST = AST.map(obj => obj.instance.content.body);
250 | for (let i = 0; i < AST.length; i++) {
251 | AST[i] = AST[i].filter(node => node.type === "ImportDeclaration");
252 | for (let j = 0; j < AST[i].length; j++) {
253 | if (AST[i][j].source.value !== "svelte") {
254 | let obj = {};
255 | obj.type = AST[i][j].type;
256 | obj.source = AST[i][j].source.value.split("");
257 | obj.source.shift();
258 | obj.source.shift();
259 | obj.source = obj.source.join("");
260 | obj.source = obj.source.replace(".svelte", "");
261 | obj.source = obj.source.slice(obj.source.lastIndexOf('/') + 1)
262 | AST[i][j] = obj;
263 | } else {
264 | let obj = {};
265 | obj.type = AST[i][j].type;
266 | obj.source = AST[i][j].source.value;
267 | AST[i][j] = obj;
268 | }
269 | }
270 | }
271 |
272 | // modified the url array to match with AST array and then combined into
273 | // bigData object
274 | for (let i = 0; i < urls.length; i++) {
275 | for (let j = urls[i].url.length - 1; j > 0; j--) {
276 | if (urls[i].url[j] === "/") {
277 | urls[i].url = urls[i].url
278 | .slice(j + 1, urls[i].url.length)
279 | .replace(".svelte", "");
280 | }
281 | }
282 | bigData[urls[i].url] = AST[i];
283 | }
284 |
285 | // iterate through bigData and made parent/child object and pushed into componentTemplate array
286 | let componentTemplate = [];
287 | function componentChildren(bigObj) {
288 | for (let eachKey in bigObj) {
289 | for (let eachObj of bigObj[eachKey]) {
290 | if (
291 | eachObj.type == "ImportDeclaration" &&
292 | eachObj.source !== "svelte"
293 | ) {
294 | let obj = {};
295 | obj.parent = eachKey;
296 | obj.child = eachObj.source;
297 | componentTemplate.push(obj);
298 | }
299 | }
300 | }
301 | }
302 | componentChildren(bigData);
303 |
304 | // added special obj for the top parent component for D3 stratifyy function to successfully create relevant array
305 | for (let i = 0; i < componentTemplate.length; i++) {
306 | let obj = {};
307 | obj.child = componentTemplate[i].parent;
308 | if (componentTemplate.every(object => object.child !== obj.child)) {
309 | if (obj.child !== "") {
310 | obj.parent = "";
311 | componentTemplate.unshift(obj);
312 | }
313 | }
314 | }
315 |
316 | // combined data from newD3Pre into componentTemplate to render state/props onto panel with D3JS
317 | for (let i = 0; i < componentTemplate.length; i++) {
318 | for (let j = 0; j < newD3Pre.length; j++) {
319 | if (componentTemplate[i].child === Object.keys(newD3Pre[j])[0]) {
320 | componentTemplate[i].data = Object.values(newD3Pre[j])[0];
321 | }
322 | }
323 | }
324 |
325 | // modified componentTemplate for data that has no States and/or Prop to render appropriate states for users
326 | // modified the data to show only Props keys for better user experience
327 | for (let i = 0; i < componentTemplate.length; i++) {
328 | if (!componentTemplate[i].hasOwnProperty("data")) {
329 | componentTemplate[i].data = {
330 | State: "No State",
331 | Props: "No Props"
332 | };
333 | } else if (
334 | Object.keys(componentTemplate[i].data.Props).length === 0
335 | ) {
336 | componentTemplate[i].data.Props = "No Props";
337 | } else {
338 | let result = [];
339 | componentTemplate[i].data.Props = result.concat(
340 | Object.keys(componentTemplate[i].data.Props)
341 | );
342 | }
343 | }
344 |
345 | // finally create templateStructured for D3 using D3.stratify function
346 | let templateStructured = d3
347 | .stratify()
348 | .id(function(d) {
349 | return d.child;
350 | })
351 | .parentId(function(d) {
352 | return d.parent;
353 | })(componentTemplate);
354 |
355 | // filter through templateStructured
356 | templateStructured = filterTree(compRecord, templateStructured);
357 | switch (tab) {
358 | case "tree":
359 | let margin = {top: 40, right: 10, bottom: 50, left: 10},
360 | width = 150 - margin.left - margin.right,//660
361 | height = 500 - margin.top - margin.bottom;
362 |
363 | // declares a tree layout and assigns the size
364 | let treemap = d3.tree()
365 | .size([width, height]);
366 |
367 |
368 | // assigns the data to a hierarchy using parent-child relationships
369 | let nodes = d3.hierarchy(templateStructured);
370 |
371 | // maps the node data to the tree layout
372 | nodes = treemap(nodes);
373 |
374 | //check if a D3 tree is already present
375 | // if so, replace tree, instead of appending tree
376 | if (!d3.select("#component-cur").empty()) {
377 | d3.select("#component-cur").remove()
378 | };
379 |
380 | let svg = d3.select("#component-tree-display").append("svg")
381 | .attr('id', 'component-cur')
382 | .attr("width", width + margin.left + margin.right)
383 | .attr("height", height + margin.top + margin.bottom),
384 | g = svg.append("g")
385 | .attr("transform",
386 | "translate(" + margin.left + "," + margin.top + ")");
387 | // adds the links between the nodes
388 | let link = g.selectAll(".link")
389 | .data( nodes.descendants().slice(1))
390 | .enter().append("path")
391 | .attr("class", "link")
392 | .attr("d", function(d) {
393 | return "M" + d.x + "," + d.y
394 | + "C" + d.x + "," + (d.y + d.parent.y) / 2
395 | + " " + d.parent.x + "," + (d.y + d.parent.y) / 2
396 | + " " + d.parent.x + "," + d.parent.y;
397 | });
398 | console.log('link', link)
399 |
400 | // adds each node as a group
401 | let node = g.selectAll(".node")
402 | .data(nodes.descendants())
403 | .enter().append("g")
404 | .attr("class", function(d) {
405 | return "node" +
406 | (d.children ? " node--internal" : " node--leaf"); })
407 | .attr("transform", function(d) {
408 | return "translate(" + d.x + "," + d.y + ")"; });
409 |
410 | // adds the circle to the node
411 | node.append("circle")
412 | .attr("r", 10);
413 |
414 | // adds the text to the node
415 | node.append("text")
416 | .attr("dy", ".35em")
417 | .attr("y", function(d) { return d.children ? -20 : 20; })
418 | .style("text-anchor", "middle")
419 | .text(function(d) { return d.data.id; });
420 |
421 | console.log('LAST NODE', node);
422 | break;
423 | case "chart":
424 | (function () {
425 | 'use strict';
426 | }());
427 | let tree = d3.tree;
428 | let hierarchy = d3.hierarchy;
429 | let select = d3.select;
430 | let data = templateStructured;
431 | let MyTree = /** @class */ (function () {
432 | function MyTree() {
433 | let _this = this;
434 | this.connector = function (d) {
435 | return "M" + d.parent.y + "," + d.parent.x
436 | + "V" + d.x + "H" + d.y;
437 | };
438 | this.collapse = function (d) {
439 | if (d.children) {
440 | d._children = d.children;
441 | d._children.forEach(_this.collapse);
442 | d.children = null;
443 | }
444 | };
445 | this.click = function (d) {
446 | if (d.children) {
447 | d._children = d.children;
448 | d.children = null;
449 | }
450 | else {
451 | d.children = d._children;
452 | d._children = null;
453 | }
454 | _this.update(d);
455 | };
456 | this.update = function (source) {
457 | _this.width = 100;
458 | // Compute the new tree layout.
459 | let nodes = _this.tree(_this.root);
460 | let nodesSort = [];
461 | nodes.eachBefore(function (n) {
462 | nodesSort.push(n);
463 | });
464 | _this.height = Math.max(500, nodesSort.length * _this.barHeight + _this.margin.top + _this.margin.bottom);
465 | let links = nodesSort.slice(1);
466 | // Compute the "layout".
467 | nodesSort.forEach(function (n, i) {
468 | n.x = i * _this.barHeight;
469 | });
470 | d3.select('svg').transition()
471 | .duration(_this.duration)
472 | .attr("height", _this.height);
473 | // Update the nodes…
474 | let node = _this.svg.selectAll('g.node')
475 | .data(nodesSort, function (d) {
476 | return d.id || (d.id = ++this.i);
477 | });
478 | // Enter any new nodes at the parent's previous position.
479 | let nodeEnter = node.enter().append('g')
480 | .attr('class', 'node')
481 | .attr('transform', function () {
482 | return 'translate(' + source.y0 + ',' + source.x0 + ')';
483 | })
484 | .on('click', _this.click);
485 | nodeEnter.append('circle')
486 | .attr('r', 1e-6)
487 | .style('fill', function (d) {
488 | return d._children ? 'lightsteelblue' : '#fff';
489 | });
490 | nodeEnter.append('text')
491 | .attr('x', function (d) {
492 | return d.children || d._children ? 10 : 10;
493 | })
494 | .attr('dy', '.35em')
495 | .attr('text-anchor', function (d) {
496 | return d.children || d._children ? 'start' : 'start';
497 | })
498 | .text(function (d) {
499 | if (d.data.id.length > 20) {
500 | return d.data.id.substring(0, 20) + '...';
501 | }
502 | else {
503 | return d.data.id;
504 | }
505 | })
506 | .style('fill-opacity', 1e-6);
507 | nodeEnter.append('svg:title').text(function (d) {
508 | return d.data.id;
509 | });
510 | // Transition nodes to their new position.
511 | let nodeUpdate = node.merge(nodeEnter)
512 | .transition()
513 | .duration(_this.duration);
514 | nodeUpdate
515 | .attr('transform', function (d) {
516 | return 'translate(' + d.y + ',' + d.x + ')';
517 | });
518 | nodeUpdate.select('circle')
519 | .attr('r', 4.5)
520 | .style('fill', function (d) {
521 | return d._children ? 'lightsteelblue' : '#fff';
522 | });
523 | nodeUpdate.select('text')
524 | .style('fill-opacity', 1);
525 | // Transition exiting nodes to the parent's new position (and remove the nodes)
526 | let nodeExit = node.exit().transition()
527 | .duration(_this.duration);
528 | nodeExit
529 | .attr('transform', function (d) {
530 | return 'translate(' + source.y + ',' + source.x + ')';
531 | })
532 | .remove();
533 | nodeExit.select('circle')
534 | .attr('r', 1e-6);
535 | nodeExit.select('text')
536 | .style('fill-opacity', 1e-6);
537 | // Update the links…
538 | let link = _this.svg.selectAll('path.link')
539 | .data(links, function (d) {
540 | // return d.target.id;
541 | let id = d.id + '->' + d.parent.id;
542 | return id;
543 | });
544 | // Enter any new links at the parent's previous position.
545 | let linkEnter = link.enter().insert('path', 'g')
546 | .attr('class', 'link')
547 | .attr('d', function (d) {
548 | let o = { x: source.x0, y: source.y0, parent: { x: source.x0, y: source.y0 } };
549 | return _this.connector(o);
550 | });
551 | // Transition links to their new position.
552 | link.merge(linkEnter).transition()
553 | .duration(_this.duration)
554 | .attr('d', _this.connector);
555 | // Transition exiting nodes to the parent's new position.
556 | link.exit().transition()
557 | .duration(_this.duration)
558 | .attr('d', function (d) {
559 | let o = { x: source.x, y: source.y, parent: { x: source.x, y: source.y } };
560 | return _this.connector(o);
561 | })
562 | .remove();
563 | // Stash the old positions for transition.
564 | nodesSort.forEach(function (d) {
565 | d.x0 = d.x;
566 | d.y0 = d.y;
567 | });
568 | };
569 | }
570 | MyTree.prototype.$onInit = function () {
571 | let _this = this;
572 | this.margin = { top: 20, right: 10, bottom: 20, left: 10 };
573 | this.width = 150 - this.margin.right - this.margin.left;
574 | this.height = 100 - this.margin.top - this.margin.bottom;
575 | this.barHeight = 20;
576 | this.barWidth = this.width * .8;
577 | this.i = 0;
578 | this.duration = 750;
579 | this.tree = tree().size([this.width, this.height]);
580 | // this.tree = tree().nodeSize([0, 30]);
581 | this.tree = tree().nodeSize([0, 30]);
582 | this.root = this.tree(hierarchy(data));
583 | this.root.each(function (d) {
584 | d.id = d.id; //transferring name to a name variable
585 | d.id = _this.i; //Assigning numerical Ids
586 | _this.i++;
587 | });
588 | this.root.x0 = this.root.x;
589 | this.root.y0 = this.root.y;
590 | if (!d3.select("#component-cur").empty()) {
591 | console.log('hit')
592 | d3.select("#component-cur").remove()
593 | };
594 | this.svg = select('#component-tree-display').append('svg')
595 | .attr('id', 'component-cur')
596 | .attr('width', this.width + this.margin.right + this.margin.left)
597 | .attr('height', this.height + this.margin.top + this.margin.bottom)
598 | .append('g')
599 | .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
600 | this.update(this.root);
601 | };
602 | return MyTree;
603 | }());
604 | ;
605 | let myTree = new MyTree();
606 | const test = myTree.$onInit();
607 | break;
608 | }
609 | }, 100);
610 | });
611 | };
--------------------------------------------------------------------------------