├── static ├── .gitkeep └── flare.json ├── .eslintignore ├── test ├── unit │ ├── setup.js │ ├── .eslintrc │ └── specs │ │ └── HelloWorld.spec.js └── e2e │ ├── specs │ └── test.js │ ├── custom-assertions │ └── elementCount.js │ ├── nightwatch.conf.js │ └── runner.js ├── config ├── prod.env.js ├── test.env.js ├── dev.env.js └── index.js ├── src ├── assets │ └── logo.png ├── router │ └── index.js ├── main.js ├── App.vue └── components │ └── Treemap.vue ├── .editorconfig ├── .babelrc ├── .postcssrc.js ├── .gitignore ├── index.html ├── .eslintrc.js ├── README.md ├── package.json └── README.html /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | -------------------------------------------------------------------------------- /test/unit/setup.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/albertopereira/vuejs-treemap/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | }, 5 | "globals": { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"] } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | /test/unit/coverage/ 8 | /test/e2e/reports/ 9 | selenium-debug.log 10 | 11 | # Editor directories and files 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Treemap from '@/components/Treemap' 4 | 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'Treemap', 12 | component: Treemap 13 | } 14 | ] 15 | }) 16 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vuejs+D3 Zoomable Treemap 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/unit/specs/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import HelloWorld from '@/components/HelloWorld' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(HelloWorld) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .toEqual('Welcome to Your Vue.js App') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | router, 13 | template: '', 14 | components: { App } 15 | }) 16 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // add your custom rules here 19 | 'rules': { 20 | // allow paren-less arrow functions 21 | 'arrow-parens': 0, 22 | // allow async-await 23 | 'generator-star-spacing': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | 4 | const webpack = require('webpack') 5 | const DevServer = require('webpack-dev-server') 6 | 7 | const webpackConfig = require('../../build/webpack.prod.conf') 8 | const devConfigPromise = require('../../build/webpack.dev.conf') 9 | 10 | let server 11 | 12 | devConfigPromise.then(devConfig => { 13 | const devServerOptions = devConfig.devServer 14 | const compiler = webpack(webpackConfig) 15 | server = new DevServer(compiler, devServerOptions) 16 | const port = devServerOptions.port 17 | const host = devServerOptions.host 18 | return server.listen(port, host) 19 | }) 20 | .then(() => { 21 | // 2. run the nightwatch test suite against it 22 | // to run in additional browsers: 23 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 24 | // 2. add it to the --env flag below 25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 26 | // For more information on Nightwatch's config file, see 27 | // http://nightwatchjs.org/guide#settings-file 28 | let opts = process.argv.slice(2) 29 | if (opts.indexOf('--config') === -1) { 30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 31 | } 32 | if (opts.indexOf('--env') === -1) { 33 | opts = opts.concat(['--env', 'chrome']) 34 | } 35 | 36 | const spawn = require('cross-spawn') 37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 38 | 39 | runner.on('exit', function (code) { 40 | server.close() 41 | process.exit(code) 42 | }) 43 | 44 | runner.on('error', function (err) { 45 | server.close() 46 | throw err 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vuejs+D3 Zoomable Treemap 2 | 3 | > An implementation, updated to d3v4, in Vuejs, of the [D3 Zoomable Treemap](https://bost.ocks.org/mike/treemap/). 4 | 5 | ## Demo 6 | 7 | Yes. [Here](http://treemap-demo.albertopereira.com). 8 | 9 | ## Dependencies 10 | 11 | [Node.js](https://nodejs.org/en/) (>=4.x, 6.x preferred) and npm version 3+. 12 | [d3](https://www.npmjs.com/package/d3) (6.x) 13 | 14 | ## Build Setup 15 | 16 | ``` bash 17 | # install dependencies 18 | npm install 19 | 20 | # serve with hot reload at localhost:8080 21 | npm run dev 22 | 23 | # build for production with minification 24 | npm run build 25 | 26 | # build for production and view the bundle analyzer report 27 | npm run build --report 28 | 29 | # run unit tests 30 | npm run unit 31 | 32 | # run e2e tests 33 | npm run e2e 34 | 35 | # run all tests 36 | npm test 37 | ``` 38 | 39 | ## Details 40 | 41 | There's only one component that matters, in src/components/Treemap.vue, and you can extract it and use it in your own projects. The source data is a JSON file in static/flare.json. If you prefer, you can use this build as a base for your project, which uses the [vuejs-webpack template](https://github.com/vuejs-templates/webpack), containing a webpack + vue-loader setup with hot reload, linting, testing & css extraction, and a router ([vue router](https://router.vuejs.org/en/)). 42 | 43 | This implementation of a D3 visualization in Vuejs basically eliminates 3d-select and the need for an explicit rerender of the svg composition. It binds attributes to svg elements, and the svg structure, explicitly defined in the template, reflects the computed data, at any moment, taking advantage of the reactive nature of vuejs. Thus, by setting events (on click events in this project) on the svg elements, a new data tree can be refactored and the changes immediatly reflected in the visualization. 44 | 45 | For a detailed explanation on how things work with [vue-cli](https://github.com/vuejs/vue-cli), check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 46 | 47 | ## ToDo 48 | 49 | Cleanup a bit the code. There are still some inline styles in the svg. 50 | Migrate some D3 function calls to Vuejs (the scales - scaleLinear and scaleOrdinal - probably). 51 | 52 | 53 | ## License 54 | 55 | [MIT](http://opensource.org/licenses/MIT) 56 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.3 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.HOST, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "closer-client", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "Alberto Pereira ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "unit": "jest test/unit/specs --coverage", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs", 14 | "build": "node build/build.js" 15 | }, 16 | "dependencies": { 17 | "d3": "^6.1.1", 18 | "d3-request": "^1.0.6", 19 | "vue": "^2.6.12", 20 | "vue-router": "^3.4.3" 21 | }, 22 | "devDependencies": { 23 | "autoprefixer": "^7.1.2", 24 | "babel-core": "^6.22.1", 25 | "babel-eslint": "^7.1.1", 26 | "babel-jest": "^21.0.2", 27 | "babel-loader": "^7.1.1", 28 | "babel-plugin-transform-runtime": "^6.22.0", 29 | "babel-preset-env": "^1.3.2", 30 | "babel-preset-stage-2": "^6.22.0", 31 | "babel-register": "^6.22.0", 32 | "chalk": "^2.0.1", 33 | "chromedriver": "^2.27.2", 34 | "copy-webpack-plugin": "^4.0.1", 35 | "cross-spawn": "^5.0.1", 36 | "css-loader": "^0.28.0", 37 | "eslint": "^3.19.0", 38 | "eslint-config-standard": "^10.2.1", 39 | "eslint-friendly-formatter": "^3.0.0", 40 | "eslint-loader": "^1.7.1", 41 | "eslint-plugin-html": "^3.0.0", 42 | "eslint-plugin-import": "^2.7.0", 43 | "eslint-plugin-node": "^5.2.0", 44 | "eslint-plugin-promise": "^3.4.0", 45 | "eslint-plugin-standard": "^3.0.1", 46 | "eventsource-polyfill": "^0.9.6", 47 | "extract-text-webpack-plugin": "^3.0.0", 48 | "file-loader": "^1.1.4", 49 | "friendly-errors-webpack-plugin": "^1.6.1", 50 | "html-webpack-plugin": "^2.30.1", 51 | "jest": "^21.2.0", 52 | "nightwatch": "^0.9.12", 53 | "node-notifier": "^5.1.2", 54 | "optimize-css-assets-webpack-plugin": "^3.2.0", 55 | "ora": "^1.2.0", 56 | "portfinder": "^1.0.13", 57 | "postcss-import": "^11.0.0", 58 | "postcss-loader": "^2.0.8", 59 | "rimraf": "^2.6.0", 60 | "selenium-server": "^3.0.1", 61 | "semver": "^5.3.0", 62 | "shelljs": "^0.7.6", 63 | "url-loader": "^0.5.8", 64 | "vue-jest": "^1.0.2", 65 | "vue-loader": "^13.3.0", 66 | "vue-style-loader": "^3.0.1", 67 | "vue-template-compiler": "^2.5.2", 68 | "webpack": "^3.6.0", 69 | "webpack-bundle-analyzer": "^2.9.0", 70 | "webpack-dev-server": "^2.9.1", 71 | "webpack-merge": "^4.1.0" 72 | }, 73 | "jest": { 74 | "moduleFileExtensions": [ 75 | "js", 76 | "json", 77 | "vue" 78 | ], 79 | "moduleNameMapper": { 80 | "^@/(.*)$": "/src/$1" 81 | }, 82 | "transform": { 83 | "^.+\\.js$": "/node_modules/babel-jest", 84 | ".*\\.(vue)$": "/node_modules/vue-jest" 85 | }, 86 | "setupFiles": [ 87 | "/test/unit/setup" 88 | ], 89 | "mapCoverage": true, 90 | "coverageDirectory": "/test/unit/coverage", 91 | "collectCoverageFrom": [ 92 | "src/**/*.{js,vue}", 93 | "!src/main.js", 94 | "!src/router/index.js", 95 | "!**/node_modules/**" 96 | ] 97 | }, 98 | "engines": { 99 | "node": ">= 4.0.0", 100 | "npm": ">= 3.0.0" 101 | }, 102 | "browserslist": [ 103 | "> 1%", 104 | "last 2 versions", 105 | "not ie <= 8" 106 | ] 107 | } 108 | -------------------------------------------------------------------------------- /src/components/Treemap.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 268 | 269 | 327 | -------------------------------------------------------------------------------- /static/flare.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "flare", 4 | "children": [ 5 | { 6 | "name": "analytics", 7 | "children": [ 8 | { 9 | "name": "cluster", 10 | "children": [ 11 | {"name": "AgglomerativeCluster", "value": 3938}, 12 | {"name": "CommunityStructure", "value": 3812}, 13 | {"name": "HierarchicalCluster", "value": 6714}, 14 | {"name": "MergeEdge", "value": 743} 15 | ] 16 | }, 17 | { 18 | "name": "graph", 19 | "children": [ 20 | {"name": "BetweennessCentrality", "value": 3534}, 21 | {"name": "LinkDistance", "value": 5731}, 22 | {"name": "MaxFlowMinCut", "value": 7840}, 23 | {"name": "ShortestPaths", "value": 5914}, 24 | {"name": "SpanningTree", "value": 3416} 25 | ] 26 | }, 27 | { 28 | "name": "optimization", 29 | "children": [ 30 | {"name": "AspectRatioBanker", "value": 7074} 31 | ] 32 | } 33 | ] 34 | }, 35 | { 36 | "name": "animate", 37 | "children": [ 38 | {"name": "Easing", "value": 17010}, 39 | {"name": "FunctionSequence", "value": 5842}, 40 | { 41 | "name": "interpolate", 42 | "children": [ 43 | {"name": "ArrayInterpolator", "value": 1983}, 44 | {"name": "ColorInterpolator", "value": 2047}, 45 | {"name": "DateInterpolator", "value": 1375}, 46 | {"name": "Interpolator", "value": 8746}, 47 | {"name": "MatrixInterpolator", "value": 2202}, 48 | {"name": "NumberInterpolator", "value": 1382}, 49 | {"name": "ObjectInterpolator", "value": 1629}, 50 | {"name": "PointInterpolator", "value": 1675}, 51 | {"name": "RectangleInterpolator", "value": 2042} 52 | ] 53 | }, 54 | {"name": "ISchedulable", "value": 1041}, 55 | {"name": "Parallel", "value": 5176}, 56 | {"name": "Pause", "value": 449}, 57 | {"name": "Scheduler", "value": 5593}, 58 | {"name": "Sequence", "value": 5534}, 59 | {"name": "Transition", "value": 9201}, 60 | {"name": "Transitioner", "value": 19975}, 61 | {"name": "TransitionEvent", "value": 1116}, 62 | {"name": "Tween", "value": 6006} 63 | ] 64 | }, 65 | { 66 | "name": "data", 67 | "children": [ 68 | { 69 | "name": "converters", 70 | "children": [ 71 | {"name": "Converters", "value": 721}, 72 | {"name": "DelimitedTextConverter", "value": 4294}, 73 | {"name": "GraphMLConverter", "value": 9800}, 74 | {"name": "IDataConverter", "value": 1314}, 75 | {"name": "JSONConverter", "value": 2220} 76 | ] 77 | }, 78 | {"name": "DataField", "value": 1759}, 79 | {"name": "DataSchema", "value": 2165}, 80 | {"name": "DataSet", "value": 586}, 81 | {"name": "DataSource", "value": 3331}, 82 | {"name": "DataTable", "value": 772}, 83 | {"name": "DataUtil", "value": 3322} 84 | ] 85 | }, 86 | { 87 | "name": "display", 88 | "children": [ 89 | {"name": "DirtySprite", "value": 8833}, 90 | {"name": "LineSprite", "value": 1732}, 91 | {"name": "RectSprite", "value": 3623}, 92 | {"name": "TextSprite", "value": 10066} 93 | ] 94 | }, 95 | { 96 | "name": "flex", 97 | "children": [ 98 | {"name": "FlareVis", "value": 4116} 99 | ] 100 | }, 101 | { 102 | "name": "physics", 103 | "children": [ 104 | {"name": "DragForce", "value": 1082}, 105 | {"name": "GravityForce", "value": 1336}, 106 | {"name": "IForce", "value": 319}, 107 | {"name": "NBodyForce", "value": 10498}, 108 | {"name": "Particle", "value": 2822}, 109 | {"name": "Simulation", "value": 9983}, 110 | {"name": "Spring", "value": 2213}, 111 | {"name": "SpringForce", "value": 1681} 112 | ] 113 | }, 114 | { 115 | "name": "query", 116 | "children": [ 117 | {"name": "AggregateExpression", "value": 1616}, 118 | {"name": "And", "value": 1027}, 119 | {"name": "Arithmetic", "value": 3891}, 120 | {"name": "Average", "value": 891}, 121 | {"name": "BinaryExpression", "value": 2893}, 122 | {"name": "Comparison", "value": 5103}, 123 | {"name": "CompositeExpression", "value": 3677}, 124 | {"name": "Count", "value": 781}, 125 | {"name": "DateUtil", "value": 4141}, 126 | {"name": "Distinct", "value": 933}, 127 | {"name": "Expression", "value": 5130}, 128 | {"name": "ExpressionIterator", "value": 3617}, 129 | {"name": "Fn", "value": 3240}, 130 | {"name": "If", "value": 2732}, 131 | {"name": "IsA", "value": 2039}, 132 | {"name": "Literal", "value": 1214}, 133 | {"name": "Match", "value": 3748}, 134 | {"name": "Maximum", "value": 843}, 135 | { 136 | "name": "methods", 137 | "children": [ 138 | {"name": "add", "value": 593}, 139 | {"name": "and", "value": 330}, 140 | {"name": "average", "value": 287}, 141 | {"name": "count", "value": 277}, 142 | {"name": "distinct", "value": 292}, 143 | {"name": "div", "value": 595}, 144 | {"name": "eq", "value": 594}, 145 | {"name": "fn", "value": 460}, 146 | {"name": "gt", "value": 603}, 147 | {"name": "gte", "value": 625}, 148 | {"name": "iff", "value": 748}, 149 | {"name": "isa", "value": 461}, 150 | {"name": "lt", "value": 597}, 151 | {"name": "lte", "value": 619}, 152 | {"name": "max", "value": 283}, 153 | {"name": "min", "value": 283}, 154 | {"name": "mod", "value": 591}, 155 | {"name": "mul", "value": 603}, 156 | {"name": "neq", "value": 599}, 157 | {"name": "not", "value": 386}, 158 | {"name": "or", "value": 323}, 159 | {"name": "orderby", "value": 307}, 160 | {"name": "range", "value": 772}, 161 | {"name": "select", "value": 296}, 162 | {"name": "stddev", "value": 363}, 163 | {"name": "sub", "value": 600}, 164 | {"name": "sum", "value": 280}, 165 | {"name": "update", "value": 307}, 166 | {"name": "variance", "value": 335}, 167 | {"name": "where", "value": 299}, 168 | {"name": "xor", "value": 354}, 169 | {"name": "_", "value": 264} 170 | ] 171 | }, 172 | {"name": "Minimum", "value": 843}, 173 | {"name": "Not", "value": 1554}, 174 | {"name": "Or", "value": 970}, 175 | {"name": "Query", "value": 13896}, 176 | {"name": "Range", "value": 1594}, 177 | {"name": "StringUtil", "value": 4130}, 178 | {"name": "Sum", "value": 791}, 179 | {"name": "Variable", "value": 1124}, 180 | {"name": "Variance", "value": 1876}, 181 | {"name": "Xor", "value": 1101} 182 | ] 183 | }, 184 | { 185 | "name": "scale", 186 | "children": [ 187 | {"name": "IScaleMap", "value": 2105}, 188 | {"name": "LinearScale", "value": 1316}, 189 | {"name": "LogScale", "value": 3151}, 190 | {"name": "OrdinalScale", "value": 3770}, 191 | {"name": "QuantileScale", "value": 2435}, 192 | {"name": "QuantitativeScale", "value": 4839}, 193 | {"name": "RootScale", "value": 1756}, 194 | {"name": "Scale", "value": 4268}, 195 | {"name": "ScaleType", "value": 1821}, 196 | {"name": "TimeScale", "value": 5833} 197 | ] 198 | }, 199 | { 200 | "name": "util", 201 | "children": [ 202 | {"name": "Arrays", "value": 8258}, 203 | {"name": "Colors", "value": 10001}, 204 | {"name": "Dates", "value": 8217}, 205 | {"name": "Displays", "value": 12555}, 206 | {"name": "Filter", "value": 2324}, 207 | {"name": "Geometry", "value": 10993}, 208 | { 209 | "name": "heap", 210 | "children": [ 211 | {"name": "FibonacciHeap", "value": 9354}, 212 | {"name": "HeapNode", "value": 1233} 213 | ] 214 | }, 215 | {"name": "IEvaluable", "value": 335}, 216 | {"name": "IPredicate", "value": 383}, 217 | {"name": "IValueProxy", "value": 874}, 218 | { 219 | "name": "math", 220 | "children": [ 221 | {"name": "DenseMatrix", "value": 3165}, 222 | {"name": "IMatrix", "value": 2815}, 223 | {"name": "SparseMatrix", "value": 3366} 224 | ] 225 | }, 226 | {"name": "Maths", "value": 17705}, 227 | {"name": "Orientation", "value": 1486}, 228 | { 229 | "name": "palette", 230 | "children": [ 231 | {"name": "ColorPalette", "value": 6367}, 232 | {"name": "Palette", "value": 1229}, 233 | {"name": "ShapePalette", "value": 2059}, 234 | {"name": "SizePalette", "value": 2291} 235 | ] 236 | }, 237 | {"name": "Property", "value": 5559}, 238 | {"name": "Shapes", "value": 19118}, 239 | {"name": "Sort", "value": 6887}, 240 | {"name": "Stats", "value": 6557}, 241 | {"name": "Strings", "value": 22026} 242 | ] 243 | }, 244 | { 245 | "name": "vis", 246 | "children": [ 247 | { 248 | "name": "axis", 249 | "children": [ 250 | {"name": "Axes", "value": 1302}, 251 | {"name": "Axis", "value": 24593}, 252 | {"name": "AxisGridLine", "value": 652}, 253 | {"name": "AxisLabel", "value": 636}, 254 | {"name": "CartesianAxes", "value": 6703} 255 | ] 256 | }, 257 | { 258 | "name": "controls", 259 | "children": [ 260 | {"name": "AnchorControl", "value": 2138}, 261 | {"name": "ClickControl", "value": 3824}, 262 | {"name": "Control", "value": 1353}, 263 | {"name": "ControlList", "value": 4665}, 264 | {"name": "DragControl", "value": 2649}, 265 | {"name": "ExpandControl", "value": 2832}, 266 | {"name": "HoverControl", "value": 4896}, 267 | {"name": "IControl", "value": 763}, 268 | {"name": "PanZoomControl", "value": 5222}, 269 | {"name": "SelectionControl", "value": 7862}, 270 | {"name": "TooltipControl", "value": 8435} 271 | ] 272 | }, 273 | { 274 | "name": "data", 275 | "children": [ 276 | {"name": "Data", "value": 20544}, 277 | {"name": "DataList", "value": 19788}, 278 | {"name": "DataSprite", "value": 10349}, 279 | {"name": "EdgeSprite", "value": 3301}, 280 | {"name": "NodeSprite", "value": 19382}, 281 | { 282 | "name": "render", 283 | "children": [ 284 | {"name": "ArrowType", "value": 698}, 285 | {"name": "EdgeRenderer", "value": 5569}, 286 | {"name": "IRenderer", "value": 353}, 287 | {"name": "ShapeRenderer", "value": 2247} 288 | ] 289 | }, 290 | {"name": "ScaleBinding", "value": 11275}, 291 | {"name": "Tree", "value": 7147}, 292 | {"name": "TreeBuilder", "value": 9930} 293 | ] 294 | }, 295 | { 296 | "name": "events", 297 | "children": [ 298 | {"name": "DataEvent", "value": 2313}, 299 | {"name": "SelectionEvent", "value": 1880}, 300 | {"name": "TooltipEvent", "value": 1701}, 301 | {"name": "VisualizationEvent", "value": 1117} 302 | ] 303 | }, 304 | { 305 | "name": "legend", 306 | "children": [ 307 | {"name": "Legend", "value": 20859}, 308 | {"name": "LegendItem", "value": 4614}, 309 | {"name": "LegendRange", "value": 10530} 310 | ] 311 | }, 312 | { 313 | "name": "operator", 314 | "children": [ 315 | { 316 | "name": "distortion", 317 | "children": [ 318 | {"name": "BifocalDistortion", "value": 4461}, 319 | {"name": "Distortion", "value": 6314}, 320 | {"name": "FisheyeDistortion", "value": 3444} 321 | ] 322 | }, 323 | { 324 | "name": "encoder", 325 | "children": [ 326 | {"name": "ColorEncoder", "value": 3179}, 327 | {"name": "Encoder", "value": 4060}, 328 | {"name": "PropertyEncoder", "value": 4138}, 329 | {"name": "ShapeEncoder", "value": 1690}, 330 | {"name": "SizeEncoder", "value": 1830} 331 | ] 332 | }, 333 | { 334 | "name": "filter", 335 | "children": [ 336 | {"name": "FisheyeTreeFilter", "value": 5219}, 337 | {"name": "GraphDistanceFilter", "value": 3165}, 338 | {"name": "VisibilityFilter", "value": 3509} 339 | ] 340 | }, 341 | {"name": "IOperator", "value": 1286}, 342 | { 343 | "name": "label", 344 | "children": [ 345 | {"name": "Labeler", "value": 9956}, 346 | {"name": "RadialLabeler", "value": 3899}, 347 | {"name": "StackedAreaLabeler", "value": 3202} 348 | ] 349 | }, 350 | { 351 | "name": "layout", 352 | "children": [ 353 | {"name": "AxisLayout", "value": 6725}, 354 | {"name": "BundledEdgeRouter", "value": 3727}, 355 | {"name": "CircleLayout", "value": 9317}, 356 | {"name": "CirclePackingLayout", "value": 12003}, 357 | {"name": "DendrogramLayout", "value": 4853}, 358 | {"name": "ForceDirectedLayout", "value": 8411}, 359 | {"name": "IcicleTreeLayout", "value": 4864}, 360 | {"name": "IndentedTreeLayout", "value": 3174}, 361 | {"name": "Layout", "value": 7881}, 362 | {"name": "NodeLinkTreeLayout", "value": 12870}, 363 | {"name": "PieLayout", "value": 2728}, 364 | {"name": "RadialTreeLayout", "value": 12348}, 365 | {"name": "RandomLayout", "value": 870}, 366 | {"name": "StackedAreaLayout", "value": 9121}, 367 | {"name": "TreeMapLayout", "value": 9191} 368 | ] 369 | }, 370 | {"name": "Operator", "value": 2490}, 371 | {"name": "OperatorList", "value": 5248}, 372 | {"name": "OperatorSequence", "value": 4190}, 373 | {"name": "OperatorSwitch", "value": 2581}, 374 | {"name": "SortOperator", "value": 2023} 375 | ] 376 | }, 377 | {"name": "Visualization", "value": 16540} 378 | ] 379 | } 380 | ] 381 | } -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | README

Vuejs+D3 Zoomable Treemap

1018 |
1019 |

An implementation, updated to d3v4, in Vuejs, of the D3 Zoomable Treemap.

1020 |
1021 |

Dependencies

1022 |

Node.js (>=4.x, 6.x preferred) and npm version 3+.

1023 |

D3V4

1024 |

Build Setup

1025 |
# install dependencies
1026 | npm install
1027 | 
1028 | # serve with hot reload at localhost:8080
1029 | npm run dev
1030 | 
1031 | # build for production with minification
1032 | npm run build
1033 | 
1034 | # build for production and view the bundle analyzer report
1035 | npm run build --report
1036 | 
1037 | # run unit tests
1038 | npm run unit
1039 | 
1040 | # run e2e tests
1041 | npm run e2e
1042 | 
1043 | # run all tests
1044 | npm test
1045 | 
1046 | 1047 |

Details

1048 |

There’s only one component that matters, in src/components/Treemap.vue, and you can extract it and use it in your own projects. The source data is a JSON file in static/flare.json. If you prefer, you can use this build as a base for the project, which uses the vuejs-webpack template, containing a webpack + vue-loader setup with hot reload, linting, testing & css extraction.

1049 |

For a detailed explanation on how things work with vue-cli, check out the guide and docs for vue-loader.

1050 |

License

1051 |

MIT

--------------------------------------------------------------------------------