Compare commits
38 Commits
Author | SHA1 | Date |
---|---|---|
Coin de Gamma | f788656bc9 | 4 years ago |
Coin de Gamma | b04d0fa0c4 | 4 years ago |
Coin de Gamma | 1baa1a366d | 5 years ago |
Alexey Velikiy | 8180e79ede | 7 years ago |
Alexey Velikiy | 81a63830a2 | 8 years ago |
Alexey Velikiy | a70f3b1621 | 8 years ago |
Alexey Velikiy | 64252ce5c7 | 8 years ago |
Alexey Velikiy | 9bd54f5b72 | 8 years ago |
Alexey Velikiy | 5c2d212cb0 | 8 years ago |
Alexey Velikiy | dba4c8b082 | 8 years ago |
Alexey Velikiy | 04dae9d895 | 8 years ago |
Alexey Velikiy | 7c7232c70b | 8 years ago |
Alexey Velikiy | d3e5bb9519 | 8 years ago |
Alexey Velikiy | 2c45320f98 | 8 years ago |
Alexey Velikiy | 929389597e | 8 years ago |
Alexey Velikiy | 869e5490d5 | 8 years ago |
Alexey Velikiy | 8cdd526cc0 | 8 years ago |
Alexey Velikiy | 621aed87ce | 8 years ago |
Alexey Velikiy | 8e91f3a2cb | 8 years ago |
Alexey Velikiy | 4afe8beebd | 8 years ago |
Alexey Velikiy | 2fbfb13871 | 8 years ago |
Alexey Velikiy | f88909e5f4 | 8 years ago |
Alexey Velikiy | 7f5a8609a0 | 8 years ago |
Alexey Velikiy | 1a9d7e8d1d | 8 years ago |
Alexey Velikiy | ec30abbb58 | 8 years ago |
Alexey Velikiy | ea3b43b137 | 8 years ago |
Alexey Velikiy | 4c653dd026 | 8 years ago |
Alexey Velikiy | fec9b58130 | 8 years ago |
Alexey Velikiy | cb6e0e90e4 | 8 years ago |
Alexey Velikiy | d89ef424fe | 8 years ago |
Alexey Velikiy | c80f015cc8 | 8 years ago |
Alexey Velikiy | 38ff651245 | 8 years ago |
Alexey Velikiy | f73be01676 | 8 years ago |
Alexey Velikiy | 1620a5f5a2 | 8 years ago |
Alexey Velikiy | bea523fc4b | 8 years ago |
Alexey Velikiy | 6f58abfc75 | 8 years ago |
Alexey Velikiy | 0ad5661ee2 | 8 years ago |
Alexey Velikiy | 0076e160c3 | 8 years ago |
52 changed files with 1968 additions and 312 deletions
@ -0,0 +1,13 @@
|
||||
{ |
||||
"presets": [ |
||||
["es2015", { "modules": false }], |
||||
"stage-2" |
||||
], |
||||
"plugins": ["transform-runtime"], |
||||
"comments": false, |
||||
"env": { |
||||
"test": { |
||||
"plugins": [ "istanbul" ] |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,9 @@
|
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
indent_style = space |
||||
indent_size = 2 |
||||
end_of_line = lf |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms |
||||
|
||||
patreon: corpglory |
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015-2017 CorpGlory Inc. |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
||||
"Software"), to deal in the Software without restriction, including |
||||
without limitation the rights to use, copy, modify, merge, publish, |
||||
distribute, sublicense, and/or sell copies of the Software, and to |
||||
permit persons to whom the Software is furnished to do so, subject to |
||||
the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,35 @@
|
||||
# d3vue |
||||
|
||||
A list of Vue.js / D3.js [examples](https://github.com/corpglory/d3vue/tree/master/src/d3-components) |
||||
|
||||
https://corpglory.github.io/d3vue/ |
||||
|
||||
## Goals |
||||
|
||||
* Collect best practices |
||||
* Make edu materials for Vue.js/D3.js learners |
||||
* Show advantages of using D3.js on top of Vue.js |
||||
|
||||
## Build Setup |
||||
|
||||
``` bash |
||||
# install dependencies |
||||
npm install |
||||
|
||||
# serve with hot reload at localhost:8080 |
||||
npm run dev |
||||
|
||||
``` |
||||
|
||||
For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). |
||||
|
||||
## License |
||||
|
||||
See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT). |
||||
|
||||
## About CorpGlory Inc. |
||||
The project developed by [CorpGlory Inc.](https://corpglory.com/), a company which provides high quality software development, data visualization, Grafana and monitoring consulting. |
||||
|
||||
See also https://chartwerk.io/ -- make your d3/vue visualisations reusable and run them in Grafana. |
||||
|
||||
Follow as on [__Twitter__](http://twitter.com/corpglory) and [__Instagram__](https://www.instagram.com/corpglory/) |
@ -0,0 +1,40 @@
|
||||
// https://github.com/shelljs/shelljs
|
||||
require('./check-versions')() |
||||
|
||||
process.env.NODE_ENV = 'production' |
||||
|
||||
var ora = require('ora') |
||||
var path = require('path') |
||||
var chalk = require('chalk') |
||||
var shell = require('shelljs') |
||||
var webpack = require('webpack') |
||||
var config = require('../config') |
||||
var webpackConfig = require('./webpack.prod.conf') |
||||
|
||||
var spinner = ora('building for production...') |
||||
spinner.start() |
||||
|
||||
var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) |
||||
shell.rm('-rf', assetsPath) |
||||
shell.mkdir('-p', assetsPath) |
||||
shell.config.silent = true |
||||
shell.cp('-R', 'static/*', assetsPath) |
||||
shell.config.silent = false |
||||
|
||||
webpack(webpackConfig, function (err, stats) { |
||||
spinner.stop() |
||||
if (err) throw err |
||||
process.stdout.write(stats.toString({ |
||||
colors: true, |
||||
modules: false, |
||||
children: false, |
||||
chunks: false, |
||||
chunkModules: false |
||||
}) + '\n\n') |
||||
|
||||
console.log(chalk.cyan(' Build complete.\n')) |
||||
console.log(chalk.yellow( |
||||
' Tip: built files are meant to be served over an HTTP server.\n' + |
||||
' Opening index.html over file:// won\'t work.\n' |
||||
)) |
||||
}) |
@ -0,0 +1,45 @@
|
||||
var chalk = require('chalk') |
||||
var semver = require('semver') |
||||
var packageConfig = require('../package.json') |
||||
|
||||
function exec (cmd) { |
||||
return require('child_process').execSync(cmd).toString().trim() |
||||
} |
||||
|
||||
var versionRequirements = [ |
||||
{ |
||||
name: 'node', |
||||
currentVersion: semver.clean(process.version), |
||||
versionRequirement: packageConfig.engines.node |
||||
}, |
||||
{ |
||||
name: 'npm', |
||||
currentVersion: exec('npm --version'), |
||||
versionRequirement: packageConfig.engines.npm |
||||
} |
||||
] |
||||
|
||||
module.exports = function () { |
||||
var warnings = [] |
||||
for (var i = 0; i < versionRequirements.length; i++) { |
||||
var mod = versionRequirements[i] |
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { |
||||
warnings.push(mod.name + ': ' + |
||||
chalk.red(mod.currentVersion) + ' should be ' + |
||||
chalk.green(mod.versionRequirement) |
||||
) |
||||
} |
||||
} |
||||
|
||||
if (warnings.length) { |
||||
console.log('') |
||||
console.log(chalk.yellow('To use this template, you must update following to modules:')) |
||||
console.log() |
||||
for (var i = 0; i < warnings.length; i++) { |
||||
var warning = warnings[i] |
||||
console.log(' ' + warning) |
||||
} |
||||
console.log() |
||||
process.exit(1) |
||||
} |
||||
} |
@ -0,0 +1,9 @@
|
||||
/* eslint-disable */ |
||||
require('eventsource-polyfill') |
||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') |
||||
|
||||
hotClient.subscribe(function (event) { |
||||
if (event.action === 'reload') { |
||||
window.location.reload() |
||||
} |
||||
}) |
@ -0,0 +1,81 @@
|
||||
require('./check-versions')() |
||||
|
||||
var config = require('../config') |
||||
if (!process.env.NODE_ENV) { |
||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) |
||||
} |
||||
|
||||
var opn = require('opn') |
||||
var path = require('path') |
||||
var express = require('express') |
||||
var webpack = require('webpack') |
||||
var proxyMiddleware = require('http-proxy-middleware') |
||||
var webpackConfig = require('./webpack.dev.conf') |
||||
|
||||
// default port where dev server listens for incoming traffic
|
||||
var port = process.env.PORT || config.dev.port |
||||
// automatically open browser, if not set will be false
|
||||
var autoOpenBrowser = !!config.dev.autoOpenBrowser |
||||
// Define HTTP proxies to your custom API backend
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
var proxyTable = config.dev.proxyTable |
||||
|
||||
var app = express() |
||||
var compiler = webpack(webpackConfig) |
||||
|
||||
var devMiddleware = require('webpack-dev-middleware')(compiler, { |
||||
publicPath: webpackConfig.output.publicPath, |
||||
quiet: true |
||||
}) |
||||
|
||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, { |
||||
log: () => {} |
||||
}) |
||||
// force page reload when html-webpack-plugin template changes
|
||||
compiler.plugin('compilation', function (compilation) { |
||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { |
||||
hotMiddleware.publish({ action: 'reload' }) |
||||
cb() |
||||
}) |
||||
}) |
||||
|
||||
// proxy api requests
|
||||
Object.keys(proxyTable).forEach(function (context) { |
||||
var options = proxyTable[context] |
||||
if (typeof options === 'string') { |
||||
options = { target: options } |
||||
} |
||||
app.use(proxyMiddleware(options.filter || context, options)) |
||||
}) |
||||
|
||||
// handle fallback for HTML5 history API
|
||||
app.use(require('connect-history-api-fallback')()) |
||||
|
||||
// serve webpack bundle output
|
||||
app.use(devMiddleware) |
||||
|
||||
// enable hot-reload and state-preserving
|
||||
// compilation error display
|
||||
app.use(hotMiddleware) |
||||
|
||||
// serve pure static assets
|
||||
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) |
||||
app.use(staticPath, express.static('./static')) |
||||
|
||||
var uri = 'http://localhost:' + port |
||||
|
||||
devMiddleware.waitUntilValid(function () { |
||||
console.log('> Listening at ' + uri + '\n') |
||||
}) |
||||
|
||||
module.exports = app.listen(port, function (err) { |
||||
if (err) { |
||||
console.log(err) |
||||
return |
||||
} |
||||
|
||||
// when env is testing, don't need open it
|
||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { |
||||
opn(uri) |
||||
} |
||||
}) |
@ -0,0 +1,64 @@
|
||||
var path = require('path') |
||||
var config = require('../config') |
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin') |
||||
|
||||
exports.assetsPath = function (_path) { |
||||
var assetsSubDirectory = process.env.NODE_ENV === 'production' |
||||
? config.build.assetsSubDirectory |
||||
: config.dev.assetsSubDirectory |
||||
return path.posix.join(assetsSubDirectory, _path) |
||||
} |
||||
|
||||
exports.cssLoaders = function (options) { |
||||
options = options || {} |
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loaders) { |
||||
var sourceLoader = loaders.map(function (loader) { |
||||
var extraParamChar |
||||
if (/\?/.test(loader)) { |
||||
loader = loader.replace(/\?/, '-loader?') |
||||
extraParamChar = '&' |
||||
} else { |
||||
loader = loader + '-loader' |
||||
extraParamChar = '?' |
||||
} |
||||
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') |
||||
}).join('!') |
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) { |
||||
return ExtractTextPlugin.extract({ |
||||
use: sourceLoader, |
||||
fallback: 'vue-style-loader' |
||||
}) |
||||
} else { |
||||
return ['vue-style-loader', sourceLoader].join('!') |
||||
} |
||||
} |
||||
|
||||
// http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
|
||||
return { |
||||
css: generateLoaders(['css']), |
||||
postcss: generateLoaders(['css']), |
||||
less: generateLoaders(['css', 'less']), |
||||
sass: generateLoaders(['css', 'sass?indentedSyntax']), |
||||
scss: generateLoaders(['css', 'sass']), |
||||
stylus: generateLoaders(['css', 'stylus']), |
||||
styl: generateLoaders(['css', 'stylus']) |
||||
} |
||||
} |
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function (options) { |
||||
var output = [] |
||||
var loaders = exports.cssLoaders(options) |
||||
for (var extension in loaders) { |
||||
var loader = loaders[extension] |
||||
output.push({ |
||||
test: new RegExp('\\.' + extension + '$'), |
||||
loader: loader |
||||
}) |
||||
} |
||||
return output |
||||
} |
@ -0,0 +1,17 @@
|
||||
var utils = require('./utils') |
||||
var config = require('../config') |
||||
var isProduction = process.env.NODE_ENV === 'production' |
||||
|
||||
module.exports = { |
||||
loaders: utils.cssLoaders({ |
||||
sourceMap: isProduction |
||||
? config.build.productionSourceMap |
||||
: config.dev.cssSourceMap, |
||||
extract: isProduction |
||||
}), |
||||
postcss: [ |
||||
require('autoprefixer')({ |
||||
browsers: ['last 2 versions'] |
||||
}) |
||||
] |
||||
} |
@ -0,0 +1,68 @@
|
||||
var path = require('path') |
||||
var utils = require('./utils') |
||||
var config = require('../config') |
||||
var vueLoaderConfig = require('./vue-loader.conf') |
||||
|
||||
function resolve (dir) { |
||||
return path.join(__dirname, '..', dir) |
||||
} |
||||
|
||||
module.exports = { |
||||
entry: { |
||||
app: './src/main.js' |
||||
}, |
||||
output: { |
||||
path: config.build.assetsRoot, |
||||
filename: '[name].js', |
||||
publicPath: process.env.NODE_ENV === 'production' |
||||
? config.build.assetsPublicPath |
||||
: config.dev.assetsPublicPath |
||||
}, |
||||
resolve: { |
||||
extensions: ['.js', '.vue', '.json'], |
||||
modules: [ |
||||
resolve('src'), |
||||
resolve('node_modules') |
||||
], |
||||
alias: { |
||||
'vue$': 'vue/dist/vue.common.js', |
||||
'src': resolve('src'), |
||||
'assets': resolve('src/assets'), |
||||
'components': resolve('src/components') |
||||
} |
||||
}, |
||||
module: { |
||||
rules: [ |
||||
{ |
||||
test: /\.scss$/, |
||||
loaders: ["style", "css", "sass"] |
||||
}, |
||||
{ |
||||
test: /\.vue$/, |
||||
loader: 'vue-loader', |
||||
options: vueLoaderConfig |
||||
}, |
||||
{ |
||||
test: /\.js$/, |
||||
loader: 'babel-loader', |
||||
include: [resolve('src'), resolve('test')] |
||||
}, |
||||
{ |
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, |
||||
loader: 'url-loader', |
||||
query: { |
||||
limit: 10000, |
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]') |
||||
} |
||||
}, |
||||
{ |
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, |
||||
loader: 'url-loader', |
||||
query: { |
||||
limit: 10000, |
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]') |
||||
} |
||||
} |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
var utils = require('./utils') |
||||
var webpack = require('webpack') |
||||
var config = require('../config') |
||||
var merge = require('webpack-merge') |
||||
var baseWebpackConfig = require('./webpack.base.conf') |
||||
var HtmlWebpackPlugin = require('html-webpack-plugin') |
||||
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') |
||||
|
||||
// add hot-reload related code to entry chunks
|
||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) { |
||||
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) |
||||
}) |
||||
|
||||
module.exports = merge(baseWebpackConfig, { |
||||
module: { |
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) |
||||
}, |
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: '#cheap-module-eval-source-map', |
||||
plugins: [ |
||||
new webpack.DefinePlugin({ |
||||
'process.env': config.dev.env |
||||
}), |
||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
||||
new webpack.HotModuleReplacementPlugin(), |
||||
new webpack.NoEmitOnErrorsPlugin(), |
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({ |
||||
filename: 'index.html', |
||||
template: 'index.html', |
||||
inject: true |
||||
}), |
||||
new FriendlyErrorsPlugin() |
||||
] |
||||
}) |
@ -0,0 +1,102 @@
|
||||
var path = require('path') |
||||
var utils = require('./utils') |
||||
var webpack = require('webpack') |
||||
var config = require('../config') |
||||
var merge = require('webpack-merge') |
||||
var baseWebpackConfig = require('./webpack.base.conf') |
||||
var HtmlWebpackPlugin = require('html-webpack-plugin') |
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin') |
||||
var env = config.build.env |
||||
|
||||
var webpackConfig = merge(baseWebpackConfig, { |
||||
module: { |
||||
rules: utils.styleLoaders({ |
||||
sourceMap: config.build.productionSourceMap, |
||||
extract: true |
||||
}) |
||||
}, |
||||
devtool: config.build.productionSourceMap ? '#source-map' : false, |
||||
output: { |
||||
path: config.build.assetsRoot, |
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'), |
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') |
||||
}, |
||||
plugins: [ |
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({ |
||||
'process.env': env |
||||
}), |
||||
new webpack.optimize.UglifyJsPlugin({ |
||||
compress: { |
||||
warnings: false |
||||
}, |
||||
sourceMap: true |
||||
}), |
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({ |
||||
filename: utils.assetsPath('css/[name].[contenthash].css') |
||||
}), |
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({ |
||||
filename: config.build.index, |
||||
template: 'index.html', |
||||
inject: true, |
||||
minify: { |
||||
removeComments: true, |
||||
collapseWhitespace: true, |
||||
removeAttributeQuotes: true |
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
}, |
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency' |
||||
}), |
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({ |
||||
name: 'vendor', |
||||
minChunks: function (module, count) { |
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return ( |
||||
module.resource && |
||||
/\.js$/.test(module.resource) && |
||||
module.resource.indexOf( |
||||
path.join(__dirname, '../node_modules') |
||||
) === 0 |
||||
) |
||||
} |
||||
}), |
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({ |
||||
name: 'manifest', |
||||
chunks: ['vendor'] |
||||
}) |
||||
] |
||||
}) |
||||
|
||||
if (config.build.productionGzip) { |
||||
var CompressionWebpackPlugin = require('compression-webpack-plugin') |
||||
|
||||
webpackConfig.plugins.push( |
||||
new CompressionWebpackPlugin({ |
||||
asset: '[path].gz[query]', |
||||
algorithm: 'gzip', |
||||
test: new RegExp( |
||||
'\\.(' + |
||||
config.build.productionGzipExtensions.join('|') + |
||||
')$' |
||||
), |
||||
threshold: 10240, |
||||
minRatio: 0.8 |
||||
}) |
||||
) |
||||
} |
||||
|
||||
if (config.build.bundleAnalyzerReport) { |
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin |
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin()) |
||||
} |
||||
|
||||
module.exports = webpackConfig |
@ -0,0 +1,6 @@
|
||||
var merge = require('webpack-merge') |
||||
var prodEnv = require('./prod.env') |
||||
|
||||
module.exports = merge(prodEnv, { |
||||
NODE_ENV: '"development"' |
||||
}) |
@ -0,0 +1,38 @@
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
var path = require('path') |
||||
|
||||
module.exports = { |
||||
build: { |
||||
env: require('./prod.env'), |
||||
index: path.resolve(__dirname, '../dist/index.html'), |
||||
assetsRoot: path.resolve(__dirname, '../dist'), |
||||
assetsSubDirectory: 'static', |
||||
assetsPublicPath: '/', |
||||
productionSourceMap: true, |
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false, |
||||
productionGzipExtensions: ['js', 'css'], |
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report |
||||
}, |
||||
dev: { |
||||
env: require('./dev.env'), |
||||
port: 8080, |
||||
autoOpenBrowser: true, |
||||
assetsSubDirectory: 'static', |
||||
assetsPublicPath: '/', |
||||
proxyTable: {}, |
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
cssSourceMap: false |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
module.exports = { |
||||
NODE_ENV: '"production"' |
||||
} |
@ -1 +1,11 @@
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><title>d3vue</title><link href=static/css/app.ea478ad0f98c40581c472cf6cea74c24.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=static/js/manifest.0d9440aa0954c24a67c3.js></script><script type=text/javascript src=static/js/vendor.03b56a03b17565331709.js></script><script type=text/javascript src=static/js/app.bb478689be3640ebf141.js></script></body></html> |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<title>d3vue</title> |
||||
</head> |
||||
<body> |
||||
<div id="app"></div> |
||||
<!-- built files will be auto injected --> |
||||
</body> |
||||
</html> |
||||
|
@ -0,0 +1,58 @@
|
||||
{ |
||||
"name": "d3vue", |
||||
"version": "1.0.0", |
||||
"description": "An educational with list of Vue.JS vs D3.js examples", |
||||
"author": "Alexey Velikiy [CorpGlory] <twitter.com/corpglory>", |
||||
"private": true, |
||||
"scripts": { |
||||
"dev": "node build/dev-server.js", |
||||
"build": "node build/build.js", |
||||
"publish": "npm run build && git checkout gh-pages && rm -rf static; rm index.html ; mv dist/static . && mv dist/index.html . && sed -i '' 's,/static,static,g' index.html && git add . && git commit -m release && git push && git checkout master" |
||||
}, |
||||
"dependencies": { |
||||
"d3": "^4.6.0", |
||||
"topojson": "^2.2.0", |
||||
"vue": "^2.1.10", |
||||
"vue-resource": "^1.2.1", |
||||
"vue-router": "^2.2.0" |
||||
}, |
||||
"devDependencies": { |
||||
"autoprefixer": "^6.7.2", |
||||
"babel-core": "^6.22.1", |
||||
"babel-loader": "^6.2.10", |
||||
"babel-plugin-transform-runtime": "^6.22.0", |
||||
"babel-preset-es2015": "^6.22.0", |
||||
"babel-preset-stage-2": "^6.22.0", |
||||
"babel-register": "^6.22.0", |
||||
"chalk": "^1.1.3", |
||||
"connect-history-api-fallback": "^1.3.0", |
||||
"css-loader": "^0.26.1", |
||||
"eventsource-polyfill": "^0.9.6", |
||||
"express": "^4.14.1", |
||||
"extract-text-webpack-plugin": "^2.0.0-rc.2", |
||||
"file-loader": "^0.10.0", |
||||
"friendly-errors-webpack-plugin": "^1.1.3", |
||||
"function-bind": "^1.1.0", |
||||
"html-webpack-plugin": "^2.28.0", |
||||
"http-proxy-middleware": "^0.17.3", |
||||
"node-sass": "^4.5.0", |
||||
"opn": "^4.0.2", |
||||
"ora": "^1.1.0", |
||||
"sass-loader": "^6.0.3", |
||||
"semver": "^5.3.0", |
||||
"shelljs": "^0.7.6", |
||||
"url-loader": "^0.5.7", |
||||
"vue-loader": "^10.3.0", |
||||
"vue-style-loader": "^2.0.0", |
||||
"vue-template-compiler": "^2.1.10", |
||||
"webpack": "^2.2.1", |
||||
"webpack-bundle-analyzer": "^2.2.1", |
||||
"webpack-dev-middleware": "^1.10.0", |
||||
"webpack-hot-middleware": "^2.16.1", |
||||
"webpack-merge": "^2.6.1" |
||||
}, |
||||
"engines": { |
||||
"node": ">= 4.0.0", |
||||
"npm": ">= 3.0.0" |
||||
} |
||||
} |
@ -0,0 +1,32 @@
|
||||
<template> |
||||
<div id="app"> |
||||
<a href='#/'> <h1> D3.js vs Vue.js examples </h1> </a> |
||||
<h2>{{ $route.name }}</h2> |
||||
<top-nav /> |
||||
<router-view></router-view> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
import topNav from './components/demos-navigation' |
||||
|
||||
export default { |
||||
name: 'app', |
||||
components: { topNav } |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
#app { |
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif; |
||||
-webkit-font-smoothing: antialiased; |
||||
-moz-osx-font-smoothing: grayscale; |
||||
text-align: center; |
||||
margin-top: 30px; |
||||
} |
||||
a { |
||||
color: black; |
||||
text-decoration: none; |
||||
} |
||||
</style> |
@ -0,0 +1,97 @@
|
||||
<template> |
||||
<div id="holder"> |
||||
<div class="links"> |
||||
<router-link v-if="prev" :to="prev.path" class="prev"> < prev </router-link> |
||||
<a :href="sourceHref" class="source"> source </a> |
||||
<router-link v-if="next" :to="next.path" class="next"> next > </router-link> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
import { routes } from 'router/demos'; |
||||
const config = require('config.json'); |
||||
|
||||
export default { |
||||
computed: { |
||||
prev: function() { |
||||
var index = this.findIndex(); |
||||
if(index == -1) { |
||||
return undefined; |
||||
} |
||||
return index > 0 ? routes[index - 1] : undefined; |
||||
}, |
||||
next: function() { |
||||
var index = this.findIndex(); |
||||
if(index == -1) { |
||||
return undefined; |
||||
} |
||||
return index + 1 < routes.length ? routes[index + 1] : undefined; |
||||
}, |
||||
sourceHref: function() { |
||||
var index = this.findIndex(); |
||||
if(index == -1) { |
||||
return config.githubLink; |
||||
} |
||||
return routes[index].source; |
||||
} |
||||
}, |
||||
methods: { |
||||
findIndex: function() { |
||||
var me = this.$route.name; |
||||
return routes.findIndex(r => r.name === me); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
|
||||
#links { |
||||
display: block; |
||||
width: 300px; |
||||
height: 40px; |
||||
position: relative; |
||||
} |
||||
|
||||
a { |
||||
display: block; |
||||
position: absolute; |
||||
width: 100px; |
||||
text-decoration: none; |
||||
font-weight: bold; |
||||
color: blue; |
||||
} |
||||
|
||||
a:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
.prev { |
||||
left: 0px; |
||||
text-align: left; |
||||
} |
||||
|
||||
.source { |
||||
left:100px; |
||||
text-align: center; |
||||
} |
||||
|
||||
.next { |
||||
right: 0px; |
||||
text-align: right; |
||||
} |
||||
|
||||
#holder { |
||||
width: 300px; |
||||
margin: auto; |
||||
position: relative; |
||||
height: 30px; |
||||
/*border-top: 1px dashed gray;*/ |
||||
border-bottom: 1px dashed gray; |
||||
padding-top: 10px; |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
} |
||||
</style> |
@ -0,0 +1,51 @@
|
||||
<template> |
||||
<div class="hello"> |
||||
<ul> |
||||
<li v-for="item in items"> |
||||
<router-link :to="item.path">{{ item.name }}</router-link> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { routes } from 'router/demos' |
||||
|
||||
export default { |
||||
data () { |
||||
return { |
||||
items: routes |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
h1, h2 { |
||||
font-weight: normal; |
||||
} |
||||
|
||||
ul { |
||||
/*list-style-type: none;*/ |
||||
padding: 0; |
||||
margin: auto; |
||||
width: 300px; |
||||
} |
||||
|
||||
li { |
||||
/*display: inline-block;*/ |
||||
margin: 0 0px; |
||||
list-style: decimal |
||||
} |
||||
|
||||
a { |
||||
color: blue; |
||||
display: block; |
||||
text-decoration: none; |
||||
text-align: left; |
||||
} |
||||
|
||||
a:hover { |
||||
text-decoration: underline;; |
||||
} |
||||
</style> |
@ -0,0 +1,4 @@
|
||||
{ |
||||
"githubLink": "https://github.com/corpglory/d3vue/", |
||||
"d3ComponentsPath": "tree/master/src/d3-components" |
||||
} |
@ -0,0 +1,9 @@
|
||||
# d3vue |
||||
|
||||
See live demos: [corpglory.github.io/d3vue](https://corpglory.github.io/d3vue) |
||||
|
||||
## Goals |
||||
|
||||
* Help to learn Vue.js by people who already know D3.js |
||||
* Show advantages of using D3.js on top of Vue.js |
||||
* Collect best practices of problem solving with good software design |
@ -0,0 +1,118 @@
|
||||
<!-- |
||||
|
||||
Links: |
||||
Object attr: https://www.w3schools.com/xml/dom_attribute.asp |
||||
Scopes css: https://github.com/vuejs/vue-loader/blob/master/docs/en/features/scoped-css.md |
||||
.vue files: https://vuejs.org/v2/guide/single-file-components.html |
||||
D3.append: https://github.com/d3/d3-selection/blob/master/src/selection/index.js |
||||
Installation of SASS tutorial: https://www.youtube.com/watch?v=fIpLr04f8Ms |
||||
SASS: http://sass-lang.com/guide |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<svg width="500" height="300"></svg> |
||||
</template> |
||||
|
||||
<script> |
||||
const d3 = require('d3'); |
||||
|
||||
export default { |
||||
mounted: function() { |
||||
|
||||
var svg = d3.select(this.$el); |
||||
var width = +svg.attr('width'); |
||||
var height = +svg.attr('height'); |
||||
|
||||
var data = [ |
||||
{name: 'one', val: 100}, |
||||
{name: 'two', val: 150}, |
||||
{name: 'three', val: 200} |
||||
]; |
||||
|
||||
var x = d3.scaleBand() |
||||
.rangeRound([0, width]).padding(0.1) |
||||
.domain(data.map(d => d.name)); |
||||
var y = d3.scaleLinear() |
||||
.rangeRound([height * 0.3 - 20, 0]) |
||||
.domain([0, d3.max(data, d => d.val)]) |
||||
|
||||
function addRectsWithName(elem, name) { |
||||
elem |
||||
.append('text') |
||||
.text(name) |
||||
.attr('x', width / 2) |
||||
.attr('y', 5) |
||||
.attr('text-anchor', 'middle'); |
||||
elem.selectAll('rect') |
||||
.data(data) |
||||
.enter() |
||||
.append('rect') |
||||
// We add attr here |
||||
.attr('x', d => x(d.name)) |
||||
.attr('class', d => d.name) |
||||
.attr('y', d => y(d.val)) |
||||
.attr('width', x.bandwidth()) |
||||
.attr('height', d => y.range()[0] - y(d.val)) |
||||
} |
||||
|
||||
|
||||
svg |
||||
.append('g') |
||||
.attr('id', 'bars-style') |
||||
.attr('transform', `translate(0, 20)`) |
||||
.call(addRectsWithName, 'Basic styles'); |
||||
|
||||
// vue loader will substitute data attribute for styles |
||||
var STYLE_MODULE_NAME = this.$el.attributes[0].name; |
||||
svg |
||||
.append('g') |
||||
.attr('transform', `translate(0, ${height * 0.3 + 20})`) |
||||
.call(addRectsWithName, 'Scoped styles') |
||||
.selectAll('rect') |
||||
.attr(STYLE_MODULE_NAME, '') |
||||
|
||||
svg |
||||
.append('g') |
||||
.attr('id', 'bars-style-sass') |
||||
.attr('transform', `translate(0, ${height * 0.6 + 20})`) |
||||
.call(addRectsWithName, 'Sass styles'); |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
#bars-style .one { |
||||
fill: #ffc300 |
||||
} |
||||
#bars-style .two { |
||||
fill: #c70039 |
||||
} |
||||
#bars-style .three { |
||||
fill: #571845 |
||||
} |
||||
|
||||
</style> |
||||
|
||||
<style scoped> |
||||
.one { |
||||
fill: #154890 |
||||
} |
||||
.two { |
||||
fill: #e1d4c0 |
||||
} |
||||
.three { |
||||
fill: #ff6600 |
||||
} |
||||
</style> |
||||
|
||||
<style lang="sass"> |
||||
#bars-style-sass |
||||
.one |
||||
fill: #AA5C39 |
||||
.two |
||||
fill: #5B9632 |
||||
.three |
||||
fill: #2A4F6E |
||||
</style> |
@ -0,0 +1,98 @@
|
||||
<!-- |
||||
|
||||
Links: |
||||
Events: https://vuejs.org/v2/guide/events.html |
||||
Computed properties: https://vuejs.org/v2/guide/computed.html |
||||
|
||||
Data: |
||||
http://worldpopulationreview.com/states/ |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<div id="holder"> |
||||
<div class="mapHolder"> |
||||
<us-map |
||||
v-on:stateSelected="onStateSelected" |
||||
v-on:stateDeselected="onStateDeselected" |
||||
/> |
||||
</div> |
||||
<tooltip |
||||
v-if="currentState" |
||||
:title="currentState.Name" |
||||
:description="currentStateDescription" |
||||
/> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
var _ = require('lodash'); |
||||
|
||||
const map = require('d3-components/basic-map-tooltip/map'); |
||||
const tooltip = require('d3-components/basic-map-tooltip/tooltip'); |
||||
|
||||
const STATES_DATA_PATH = 'static/data/states-data.csv'; |
||||
|
||||
// lets load with vue-resource, but parse with d3 |
||||
// just because we can |
||||
import * as d3 from 'd3-dsv'; |
||||
|
||||
|
||||
export default { |
||||
components: { |
||||
usMap: map, |
||||
tooltip: tooltip |
||||
}, |
||||
created: function() { |
||||
var that = this; |
||||
|
||||
this.$http.get(STATES_DATA_PATH) |
||||
.then(function(res) { |
||||
this.statesData = {}; |
||||
d3.dsvFormat(';') |
||||
.parse(res.data, d => { |
||||
var population = d["2017 Population"].split(',').join(''); |
||||
d.value = +population; |
||||
that.statesData[d.STATE_ABBR] = d; |
||||
delete d["2017 Population"]; |
||||
delete d["STATE_ABBR"]; |
||||
return d; |
||||
}); |
||||
}) |
||||
}, |
||||
data: function() { |
||||
return { |
||||
statesData: undefined, |
||||
currentState: undefined |
||||
} |
||||
}, |
||||
computed: { |
||||
currentStateDescription: function() { |
||||
return "Population: " + this.currentState.value; |
||||
} |
||||
}, |
||||
methods: { |
||||
onStateSelected: function(stateCode) { |
||||
this.currentState = this.statesData[stateCode]; |
||||
}, |
||||
onStateDeselected: function(stateCode) { |
||||
this.currentState = undefined; |
||||
} |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<style scoped> |
||||
#holder { |
||||
position: relative; |
||||
height: 300px; |
||||
width: 500px; |
||||
margin: auto; |
||||
} |
||||
.mapHolder { |
||||
position: absolute; |
||||
margin: auto; |
||||
} |
||||
</style> |
@ -0,0 +1,64 @@
|
||||
<!-- |
||||
|
||||
It would be great if you color the map by population using data from index.vue |
||||
|
||||
Based on: |
||||
http://bl.ocks.org/rveciana/a2a1c21ca1c71cd3ec116cc911e5fce9 |
||||
http://bl.ocks.org/mapsam/6083585 |
||||
|
||||
|
||||
Links: |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<svg width="500" height="300"></svg> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
const d3 = require('d3'); |
||||
const topojson = require('topojson') |
||||
|
||||
export default { |
||||
mounted: function() { |
||||
var v = this; |
||||
var svg = d3.select(this.$el); |
||||
var width = +svg.attr('width'); |
||||
var height = +svg.attr('height'); |
||||
|
||||
var projection = d3.geoAlbersUsa(); |
||||
var path = d3.geoPath().projection(projection); |
||||
|
||||
d3.json("static/data/us.json", function(error, us) { |
||||
var g = svg.append('g'); |
||||
g |
||||
.selectAll('.state') |
||||
.data(topojson.feature(us, us.objects.usStates).features) |
||||
.enter() |
||||
.append("path") |
||||
.attr("class", "state") |
||||
.attr("d", path) |
||||
.on('mouseover', function(d) { |
||||
v.$emit('stateSelected', d.properties.STATE_ABBR) |
||||
}) |
||||
.on('mouseout', function(d) { |
||||
v.$emit('stateDeselected', d.properties.STATE_ABBR) |
||||
}) |
||||
g.attr('transform', 'scale(0.57)') |
||||
}); |
||||
|
||||
} |
||||
// TODO: fire events |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
.state { |
||||
fill: #ccc; |
||||
stroke: #fff; |
||||
} |
||||
.state:hover { |
||||
fill: steelblue; |
||||
} |
||||
</style> |
@ -0,0 +1,67 @@
|
||||
<template> |
||||
<div id="tooltipPositioner"> |
||||
<div id="tooltip"> |
||||
<div id="tooltipContainer"> |
||||
<div class="title">{{title}}</div> |
||||
<div class="description">{{description}}</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
module.exports = { |
||||
name: 'tooltip', |
||||
props: ['title', 'description'] |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<style scoped> |
||||
|
||||
#tooltipPositioner { |
||||
position: relative; |
||||
left: 50%; |
||||
top: 350px; |
||||
width: 240px; |
||||
} |
||||
|
||||
#tooltipContainer { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 230px; |
||||
left: -125px; |
||||
font-size: 12px; |
||||
line-height: 16px; |
||||
padding: 10px; |
||||
border-radius: 3px; |
||||
background: rgba(255,255,255,0.9); |
||||
color: #000; |
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4); |
||||
-moz-box-shadow: 0 1px 5px rgba(0,0,0,0.4); |
||||
border:1px solid rgba(200,200,200,0.85); |
||||
text-align:center; |
||||
} |
||||
|
||||
#tooltip { |
||||
text-align:center; |
||||
z-index: 1000; |
||||
position: absolute; |
||||
display: block; |
||||
} |
||||
|
||||
#tooltip .description { |
||||
color:#666; |
||||
font-size: 11px; |
||||
text-align:center; |
||||
font-style:italic; |
||||
} |
||||
|
||||
#tooltip .title { |
||||
text-align: left; |
||||
font-size: 13px; |
||||
text-align:center; |
||||
} |
||||
|
||||
</style> |
@ -0,0 +1,43 @@
|
||||
<!-- |
||||
|
||||
Based on: |
||||
|
||||
Links: |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<svg width="600" height="500"></svg> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
import PH2 from './ph2/index'; |
||||
const d3 = require('d3'); |
||||
|
||||
export default { |
||||
props: ['groupBy', 'data'], |
||||
watch: { |
||||
groupBy: function(groupBy) { |
||||
this.ph2.setLayout(groupBy); |
||||
}, |
||||
data: function(data) { |
||||
this.ph2.setData(data); |
||||
} |
||||
}, |
||||
mounted: function() { |
||||
var svg = d3.select(this.$el); |
||||
var width = +svg.attr('width'); |
||||
var height = +svg.attr('height'); |
||||
|
||||
var that = this; |
||||
var bubblesG = svg.append('g').attr('transform', `translate(${width/2}, ${height/2})`) |
||||
|
||||
// TODO: remove it later |
||||
d3.csv('static/data/earthquakes.csv', function(data) { |
||||
that.ph2 = new PH2(bubblesG, data, that.groupBy); |
||||
}); |
||||
} |
||||
|
||||
} |
||||
</script> |
@ -0,0 +1,102 @@
|
||||
<!-- |
||||
|
||||
Explanation: |
||||
It is not really nester routes. |
||||
It is magic of aliases and $watch route. |
||||
See /src/router/demos.js (Bubbles: nested routes part) |
||||
and /src/router/index.js |
||||
|
||||
Links: |
||||
Dynamic-matching: https://router.vuejs.org/en/essentials/dynamic-matching.html |
||||
Nested Routes: https://router.vuejs.org/en/essentials/nested-routes.html |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<div class="holder"> |
||||
<!-- <h4>Earthquakes in september 2012</h4> --> |
||||
<groupMenu :links="links" :activeLink="activeLink" /> |
||||
<bubbles :groupBy="activeLink.layout" /> |
||||
|
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
const menu = require('d3-components/bubbles-nested-routes/menu'); |
||||
const bubbles = require('d3-components/bubbles-nested-routes/bubbles'); |
||||
|
||||
const MY_URL_PREFIX = 'bubbles-nested-routes'; |
||||
const _ = require('lodash'); |
||||
|
||||
const LINKS = [ |
||||
{ |
||||
name: 'None', |
||||
path: '', |
||||
layout: 'total' |
||||
}, |
||||
{ |
||||
name: 'By country', |
||||
path: '/country', |
||||
layout: 'country' |
||||
}, |
||||
{ |
||||
name: 'By day', |
||||
path: '/day', |
||||
layout: 'day' |
||||
} |
||||
].map(d => { |
||||
d.path = '#/' + MY_URL_PREFIX + d.path; |
||||
d.active = false; |
||||
return d; |
||||
}); |
||||
|
||||
|
||||
export default { |
||||
components: { |
||||
groupMenu: menu, |
||||
bubbles: bubbles |
||||
}, |
||||
data: function() { |
||||
return { |
||||
activeLink: this.findActiveLink() |
||||
} |
||||
}, |
||||
computed: { |
||||
links: function() { |
||||
return LINKS; |
||||
} |
||||
}, |
||||
methods: { |
||||
findActiveLink: function() { |
||||
_.each(LINKS, l => { |
||||
l.active = false; |
||||
}) |
||||
var link = _.find(LINKS, l => l.path == '#' + this.$route.path); |
||||
if(!link) { |
||||
link = LINKS[0]; |
||||
} |
||||
return link; |
||||
} |
||||
}, |
||||
watch: { |
||||
'$route' (to, from) { |
||||
this.activeLink = this.findActiveLink(); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.holder { |
||||
width: 500px; |
||||
margin: auto; |
||||
} |
||||
.menu ul { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
.menu li { |
||||
text-align: left; |
||||
} |
||||
</style> |
@ -0,0 +1,48 @@
|
||||
<template> |
||||
<div class="holder"> |
||||
<ul class="menu"> |
||||
<li>Group by: </li> |
||||
<li v-for="link in alinks"> |
||||
<a :href="link.item.path" :class="{active: link.active}"> {{link.item.name}} </a> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
const _ = require('lodash'); |
||||
|
||||
export default { |
||||
props: ['links', 'activeLink'], |
||||
computed: { |
||||
alinks: function() { |
||||
var that = this; |
||||
return _.map(this.links, l => ({ |
||||
item: l, |
||||
active: (l.path == that.activeLink.path) |
||||
})) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.menu { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
.menu li { |
||||
text-align: left; |
||||
display: inline-block; |
||||
text-align: left; |
||||
margin: 0px; |
||||
margin-right: 10px; |
||||
} |
||||
.menu li a { |
||||
text-decoration: none; |
||||
} |
||||
.menu li a.active { |
||||
text-decoration: underline; |
||||
} |
||||
</style> |
@ -0,0 +1,98 @@
|
||||
// http://vallandingham.me/bubble_charts_with_d3v4.html
|
||||
|
||||
import layoutTotal from './layout-total'; |
||||
import layoutCountry from './layout-contry'; |
||||
import layoutDay from './layout-day'; |
||||
|
||||
const d3 = require('d3'); |
||||
import _ from 'lodash'; |
||||
|
||||
// TODO: do it d3-way so I can use selection.call()
|
||||
|
||||
export default class PH2 { |
||||
constructor(elem, data, layoutName) { |
||||
this.svg = elem; |
||||
this.data = data; |
||||
this.setData(data); |
||||
this._init(); |
||||
this.layout = undefined; |
||||
this.setLayout(layoutName); |
||||
} |
||||
|
||||
setLayout(layoutName) { |
||||
|
||||
if(layoutName === undefined) { |
||||
throw new Error('layoutName is undefined'); |
||||
} |
||||
if(!this.layouts) { |
||||
throw new Error('Layouts are not defined'); |
||||
} |
||||
if(!this.layouts[layoutName]) { |
||||
throw new Error('Can`t find layout ' + layoutName); |
||||
} |
||||
|
||||
if(this.layout) { |
||||
this.layout.exit(); |
||||
} |
||||
this.layout = this.layouts[layoutName]; |
||||
if(!this.layout.inited) { |
||||
this.layout.init(); |
||||
this.layout.inited = true; |
||||
} |
||||
this.layout.enter(); |
||||
this.simulation.alpha(1); |
||||
this.simulation.restart(); |
||||
} |
||||
|
||||
setData(data) { |
||||
this.nodes = data.map(d => ({ |
||||
r: +d.Magnitude |
||||
})) |
||||
} |
||||
|
||||
_init() { |
||||
this.simulation = d3.forceSimulation() |
||||
.force("index-collide", d3.forceCollide(d => d.r + 5).iterations(16)) |
||||
.force("index-x", d3.forceX().strength(0.04)) |
||||
.force("index-y", d3.forceY().strength(0.04)) |
||||
|
||||
this._initLayouts(); |
||||
|
||||
var node = this.svg.append("g") |
||||
.attr("class", "nodes") |
||||
.selectAll("circle") |
||||
.data(this.nodes) |
||||
.enter() |
||||
.append("circle") |
||||
.attr("r", d => d.r ) |
||||
|
||||
var that = this; |
||||
var ticked = function() { |
||||
node |
||||
.attr("cx", d => d.x ) |
||||
.attr("cy", d => d.y ); |
||||
if(that.layout.ticked) { |
||||
that.layout.ticked(); |
||||
} |
||||
} |
||||
|
||||
this.simulation |
||||
.nodes(this.nodes) |
||||
.on("tick", ticked); |
||||
|
||||
} |
||||
|
||||
_initLayouts() { |
||||
this.layouts = { |
||||
'total': layoutTotal, |
||||
'country': layoutCountry, |
||||
'day': layoutDay |
||||
}; |
||||
|
||||
for (var k in this.layouts) { |
||||
var v = this.layouts[k]; |
||||
this.layouts[k] = new v(this.svg, this.data, this.simulation); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,97 @@
|
||||
const d3 = require('d3'); |
||||
const _ = require('lodash'); |
||||
|
||||
export default class { |
||||
constructor(elem, data, simulation) { |
||||
this.elem = elem; |
||||
this.data = data; |
||||
this.simulation = simulation; |
||||
} |
||||
|
||||
init() { |
||||
var groups = _(this.data) |
||||
.map((k, i) => ({ |
||||
location: k.Location.split(', ')[1], |
||||
index: i |
||||
})) |
||||
.groupBy('location') |
||||
.value(); |
||||
|
||||
this.countries = _.map(groups, (v, k) => ({ key: k, r: -30 })); |
||||
|
||||
this.links = []; |
||||
console.log(groups[this.countries[0].key][0]); |
||||
for(var i = 0; i < this.countries.length; i++) { |
||||
for(var j = 0; j < groups[this.countries[i].key].length; j++) { |
||||
this.links.push({ |
||||
source: i + this.data.length, |
||||
target: groups[this.countries[i].key][j].index |
||||
}); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
enter() { |
||||
|
||||
this.nodesBefore = this.simulation.nodes(); |
||||
this.simulation |
||||
.force("country-link", d3.forceLink().id(d => d.index)) |
||||
.force("country-charge", d3.forceManyBody().strength(-30)) |
||||
.force("country-x", d3.forceX().strength(0.11)) |
||||
.force("country-y", d3.forceY().strength(0.11)) |
||||
|
||||
//console.log(this.simulation.force("link").distance());
|
||||
this.simulation.force("link")//.distance(-10)
|
||||
|
||||
this.simulation.nodes(_.concat(this.nodesBefore, this.countries)); |
||||
|
||||
this.countryG = this.elem.append("g"); |
||||
this.countyLabels = this.countryG |
||||
.selectAll('text') |
||||
.data(this.countries) |
||||
.enter() |
||||
.append('text') |
||||
.text(d => d.key) |
||||
.attr("text-anchor", "middle") |
||||
.attr("font-size", "8") |
||||
|
||||
this.linesG = this.elem.insert("g", ":first-child"); |
||||
this.lines = this.linesG |
||||
.selectAll("line") |
||||
.data(this.links) |
||||
.enter() |
||||
.append("line") |
||||
.attr("stroke", "#d7d7d7") |
||||
|
||||
|
||||
this.simulation |
||||
.force("country-link") |
||||
.links(this.links); |
||||
|
||||
} |
||||
|
||||
ticked() { |
||||
this.lines |
||||
.attr("x1", d => d.source.x) |
||||
.attr("y1", d => d.source.y) |
||||
.attr("x2", d => d.target.x) |
||||
.attr("y2", d => d.target.y); |
||||
this.countyLabels |
||||
.attr('x', d => d.x) |
||||
.attr('y', d => d.y) |
||||
} |
||||
|
||||
exit() { |
||||
this.simulation |
||||
.nodes(this.nodesBefore); |
||||
this.simulation |
||||
.force("country-link", null) |
||||
.force("country-charge", null) |
||||
.force("country-x", null) |
||||
.force("country-y", null) |
||||
|
||||
this.linesG.remove(); |
||||
this.countryG.remove(); |
||||
} |
||||
} |
@ -0,0 +1,56 @@
|
||||
const d3 = require('d3'); |
||||
const _ = require('lodash'); |
||||
|
||||
const DAY_RANGE = d3.range(14, 24); |
||||
const WIDTH = 500; |
||||
|
||||
export default class { |
||||
constructor(elem, data, simulation) { |
||||
this.elem = elem; |
||||
this.data = data; |
||||
this.simulation = simulation; |
||||
} |
||||
init() { |
||||
this.dayX = _.map( |
||||
this.data, d => this._dayToX(+d.Date.split('-')[0]) |
||||
); |
||||
} |
||||
enter() { |
||||
this.forceIndexCollide = this.simulation.force("index-collide"); |
||||
this.simulation.force("index-collide", null); |
||||
this.forceIndexY = this.simulation.force("index-y"); |
||||
this.simulation.force("index-y", null); |
||||
|
||||
this.simulation.force("day-collide", d3.forceCollide(d => d.r + 2).iterations(16)) |
||||
|
||||
|
||||
this.daysG = this.elem.append('g'); |
||||
|
||||
this.daysG |
||||
.selectAll('text') |
||||
.data(DAY_RANGE) |
||||
.enter() |
||||
.append('text') |
||||
.text(d => d) |
||||
.attr('x', this._dayToX) |
||||
.attr('font-size', 10) |
||||
.attr('fill', 'gray') |
||||
.attr('text-anchor', 'middle') |
||||
|
||||
var that = this; |
||||
this.simulation.force( |
||||
'day-x', d3.forceX(d => that.dayX[d.index]).strength(1) |
||||
); |
||||
this.simulation.force("day-y", d3.forceY().strength(0.005)); |
||||
} |
||||
exit() { |
||||
this.daysG.remove(); |
||||
this.simulation.force('day-x', null); |
||||
this.simulation.force("index-collide", this.forceIndexCollide); |
||||
this.simulation.force("index-y", this.forceIndexY); |
||||
} |
||||
|
||||
_dayToX(day) { |
||||
return (day - DAY_RANGE[0]) * WIDTH / DAY_RANGE.length - WIDTH * 0.48 |
||||
} |
||||
} |
@ -0,0 +1,15 @@
|
||||
export default class { |
||||
constructor(elem, data, simulation) { |
||||
this.elem = elem; |
||||
this.simulation = simulation; |
||||
} |
||||
init() { |
||||
|
||||
} |
||||
enter() { |
||||
|
||||
} |
||||
exit() { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
<!-- |
||||
Links: |
||||
Components: https://vuejs.org/v2/guide/components.html |
||||
.vue files: https://vuejs.org/v2/guide/single-file-components.html |
||||
|
||||
Advanced: |
||||
Component Lifecyrcle: https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram |
||||
Virtual DOM: https://medium.com/js-dojo/whats-new-in-vue-js-2-0-virtual-dom-dc4b5b827f40#.hexwxh9m3 |
||||
--> |
||||
|
||||
<template> |
||||
<svg width="500" height="300"></svg> |
||||
</template> |
||||
|
||||
<script> |
||||
const d3 = require('d3'); |
||||
export default { |
||||
mounted: function() { |
||||
// this.#el - is the root element in <template> |
||||
// in this case it is <svg> tag |
||||
d3.select(this.$el) |
||||
.append('circle') |
||||
.attr('cx', '250') |
||||
.attr('cy', '150') |
||||
.attr('r', '100') |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
</style> |
@ -0,0 +1,61 @@
|
||||
<!-- |
||||
|
||||
Links: |
||||
Local Registration: https://vuejs.org/v2/guide/components.html#Local-Registration |
||||
Props: https://vuejs.org/v2/guide/components.html#Passing-Data-with-Props |
||||
Methods: https://vuejs.org/v2/guide/events.html#Method-Event-Handlers |
||||
Conditional Rendering: https://vuejs.org/v2/guide/conditional.html |
||||
|
||||
Data: |
||||
http://www.studentsoftheworld.info/penpals/stats.php3?Pays= |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<div> |
||||
<h4>Most popular female names in the world</h4> |
||||
<pie :data="names" /> |
||||
<br> |
||||
<button v-if="canAddAName" v-on:click="addName">Add a name</button> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
var _ = require('lodash') |
||||
const pie = require('d3-components/pie-chart-local-component/pie') |
||||
|
||||
const NAMES = [ |
||||
{ name: 'Sarah', value: 2502 }, |
||||
{ name: 'Emma', value: 2005 }, |
||||
{ name: 'Laura', value: 1968 }, |
||||
{ name: 'Chloé', value: 1863 }, |
||||
{ name: 'Marie', value: 1810 }, |
||||
{ name: 'Emily', value: 1637 }, |
||||
{ name: 'Léa', value: 1592 }, |
||||
{ name: 'Camille', value: 1572 }, |
||||
{ name: 'Anna', value: 1433 }, |
||||
{ name: 'Manon', value: 1403 } |
||||
] |
||||
|
||||
export default { |
||||
components: { |
||||
pie: pie |
||||
}, |
||||
data: function() { |
||||
return { |
||||
names: _.take(NAMES, 3) |
||||
} |
||||
}, |
||||
computed: { |
||||
canAddAName: function() { |
||||
return this.names.length < NAMES.length; |
||||
} |
||||
}, |
||||
methods: { |
||||
addName: function() { |
||||
this.names.push(NAMES[this.names.length]); |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,92 @@
|
||||
<!-- |
||||
|
||||
Based on: |
||||
https://bl.ocks.org/shimizu/f90651541575f348a129444003a73467 |
||||
|
||||
Links: |
||||
Props: https://vuejs.org/v2/guide/components.html#Passing-Data-with-Props |
||||
Methods: https://vuejs.org/v2/guide/events.html#Method-Event-Handlers |
||||
|
||||
--> |
||||
|
||||
<template> |
||||
<svg width="500" height="300"></svg> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
const d3 = require('d3'); |
||||
|
||||
export default { |
||||
mounted: function() { |
||||
var svg = d3.select(this.$el); |
||||
var width = +svg.attr('width'); |
||||
var height = +svg.attr('height'); |
||||
|
||||
var margin = { top:20, left:0, bottom:30, right:0 }; |
||||
|
||||
var chartWidth = width - (margin.left + margin.right); |
||||
var chartHeight = height - (margin.top + margin.bottom); |
||||
|
||||
this.chartLayer = svg |
||||
.append('g') |
||||
.attr( |
||||
"transform", |
||||
`translate(${margin.left}, ${margin.top})` |
||||
); |
||||
|
||||
this.arc = d3.arc() |
||||
.outerRadius(chartHeight / 2) |
||||
.innerRadius(chartHeight / 4) |
||||
.padAngle(0.03) |
||||
.cornerRadius(8) |
||||
|
||||
this.pieG = this.chartLayer |
||||
.append("g") |
||||
.attr( |
||||
"transform", |
||||
`translate(${chartWidth / 2}, ${chartHeight / 2})` |
||||
) |
||||
|
||||
this.drawChart(this.data); |
||||
|
||||
}, |
||||
props: ['data'], |
||||
watch: { |
||||
data: function(newData) { |
||||
this.drawChart(newData); |
||||
} |
||||
}, |
||||
methods: { |
||||
drawChart: function(data) { |
||||
var arcs = d3.pie() |
||||
.sort(null) |
||||
.value(function(d) { return d.value; }) |
||||
(data) |
||||
|
||||
var block = this.pieG.selectAll(".arc") |
||||
.data(arcs) |
||||
|
||||
block.select('path').attr('d', this.arc) |
||||
|
||||
var newBlock = block |
||||
.enter() |
||||
.append("g") |
||||
.classed("arc", true) |
||||
|
||||
newBlock.append("path") |
||||
.attr("d", this.arc) |
||||
.attr("id", function(d, i) { return "arc-" + i }) |
||||
.attr("stroke", "gray") |
||||
.attr("fill", d => d3.interpolateCool(Math.random())) |
||||
|
||||
newBlock.append("text") |
||||
.attr("dx", 10) |
||||
.attr("dy", -5) |
||||
.append("textPath") |
||||
.attr("xlink:href", function(d, i) { return "#arc-" + i; }) |
||||
.text(function(d) { return d.data.name }) |
||||
} |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,49 @@
|
||||
<!-- |
||||
Links |
||||
Data: https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function |
||||
Form Input Bindings: https://vuejs.org/v2/guide/forms.html#Basic-Usage |
||||
Watchers: https://vuejs.org/v2/guide/computed.html#Watchers |
||||
--> |
||||
|
||||
<template> |
||||
<div> |
||||
<svg width="500" height="300"></svg> |
||||
<br> |
||||
<input |
||||
type="range" |
||||
v-model="circleSize" |
||||
min="1" |
||||
max="100" |
||||
step="1" |
||||
> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
const d3 = require('d3'); |
||||
export default { |
||||
data: function() { |
||||
return { |
||||
circleSize: 50 |
||||
} |
||||
}, |
||||
mounted: function(createElement) { |
||||
var svg = d3.select(this.$el).select('svg'); |
||||
this.circle = svg |
||||
.append('circle') |
||||
.attr('cx', '250') |
||||
.attr('cy', '150') |
||||
.attr('r', this.circleSize) |
||||
}, |
||||
watch: { |
||||
circleSize: function(newValue) { |
||||
this.circle |
||||
.attr('r', newValue) |
||||
} |
||||
} |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style> |
||||
</style> |
@ -0,0 +1,16 @@
|
||||
// The Vue build version to load with the `import` command
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue' |
||||
import app from './app' |
||||
import router from './router' |
||||
|
||||
import VueResource from 'vue-resource' |
||||
Vue.use(VueResource); |
||||
|
||||
/* eslint-disable no-new */ |
||||
new Vue({ |
||||
el: '#app', |
||||
router, |
||||
template: '<app/>', |
||||
components: { app } |
||||
}) |
@ -0,0 +1,45 @@
|
||||
const config = require('config.json'); |
||||
|
||||
export const routes = [ |
||||
{ |
||||
name: 'Circle: mount', |
||||
path: '/circle-mount', |
||||
component: require('d3-components/circle-mount') |
||||
}, |
||||
{ |
||||
name: 'Circle: size controller', |
||||
path: '/size-controller', |
||||
component: require('d3-components/size-controller') |
||||
}, |
||||
{ |
||||
name: 'Bars: styles', |
||||
path: '/bars-styles', |
||||
component: require('d3-components/bars-styles') |
||||
}, |
||||
{ |
||||
name: 'Pie chart: local component & props', |
||||
path: '/pie-chart-local-component', |
||||
folder: true, |
||||
component: require('d3-components/pie-chart-local-component/index') |
||||
}, |
||||
{ |
||||
name: 'Basic map: html tooltip & events', |
||||
path: '/basic-map-tooltip', |
||||
folder: true, |
||||
component: require('d3-components/basic-map-tooltip/index') |
||||
}, |
||||
{ |
||||
name: 'Bubbles: nested routes', |
||||
path: '/bubbles-nested-routes', |
||||
alias: '/bubbles-nested-routes/*', |
||||
folder: true, |
||||
component: require('d3-components/bubbles-nested-routes/index') |
||||
} |
||||
].map(r => { |
||||
var res = r; |
||||
res.source = config.githubLink + |
||||
config.d3ComponentsPath + |
||||
r.path + |
||||
(r.folder ? '' : '.vue') |
||||
return res; |
||||
}) |
@ -0,0 +1,17 @@
|
||||
import Vue from 'vue' |
||||
import VueRouter from 'vue-router' |
||||
import Index from 'components/index' |
||||
import {routes as demoRoutes} from './demos' |
||||
|
||||
Vue.use(VueRouter) |
||||
|
||||
export default new VueRouter({ |
||||
routes: [ |
||||
{ |
||||
path: '/', |
||||
name: 'Menu', |
||||
component: Index |
||||
}, ... demoRoutes |
||||
|
||||
] |
||||
}) |
@ -1,278 +0,0 @@
|
||||
|
||||
#app[data-v-41b7bac0] { |
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif; |
||||
-webkit-font-smoothing: antialiased; |
||||
-moz-osx-font-smoothing: grayscale; |
||||
text-align: center; |
||||
margin-top: 30px; |
||||
} |
||||
a[data-v-41b7bac0] { |
||||
color: black; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
#links[data-v-098bb42e] { |
||||
display: block; |
||||
width: 300px; |
||||
height: 40px; |
||||
position: relative; |
||||
} |
||||
a[data-v-098bb42e] { |
||||
display: block; |
||||
position: absolute; |
||||
width: 100px; |
||||
text-decoration: none; |
||||
font-weight: bold; |
||||
color: blue; |
||||
} |
||||
a[data-v-098bb42e]:hover { |
||||
text-decoration: underline; |
||||
} |
||||
.prev[data-v-098bb42e] { |
||||
left: 0px; |
||||
text-align: left; |
||||
} |
||||
.source[data-v-098bb42e] { |
||||
left:100px; |
||||
text-align: center; |
||||
} |
||||
.next[data-v-098bb42e] { |
||||
right: 0px; |
||||
text-align: right; |
||||
} |
||||
#holder[data-v-098bb42e] { |
||||
width: 300px; |
||||
margin: auto; |
||||
position: relative; |
||||
height: 30px; |
||||
/*border-top: 1px dashed gray;*/ |
||||
border-bottom: 1px dashed gray; |
||||
padding-top: 10px; |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#bars-style .one { |
||||
fill: #ffc300 |
||||
} |
||||
#bars-style .two { |
||||
fill: #c70039 |
||||
} |
||||
#bars-style .three { |
||||
fill: #571845 |
||||
} |
||||
|
||||
|
||||
.one[data-v-63d4ce13] { |
||||
fill: #154890 |
||||
} |
||||
.two[data-v-63d4ce13] { |
||||
fill: #e1d4c0 |
||||
} |
||||
.three[data-v-63d4ce13] { |
||||
fill: #ff6600 |
||||
} |
||||
|
||||
#bars-style-sass .one { |
||||
fill: #AA5C39; |
||||
} |
||||
#bars-style-sass .two { |
||||
fill: #5B9632; |
||||
} |
||||
#bars-style-sass .three { |
||||
fill: #2A4F6E; |
||||
} |
||||
|
||||
#holder[data-v-39fd153a] { |
||||
position: relative; |
||||
height: 300px; |
||||
width: 500px; |
||||
margin: auto; |
||||
} |
||||
.mapHolder[data-v-39fd153a] { |
||||
position: absolute; |
||||
margin: auto; |
||||
} |
||||
|
||||
.state { |
||||
fill: #ccc; |
||||
stroke: #fff; |
||||
} |
||||
.state:hover { |
||||
fill: steelblue; |
||||
} |
||||
|
||||
#tooltipPositioner[data-v-6039702a] { |
||||
position: relative; |
||||
left: 50%; |
||||
top: 350px; |
||||
width: 240px; |
||||
} |
||||
#tooltipContainer[data-v-6039702a] { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 230px; |
||||
left: -125px; |
||||
font-size: 12px; |
||||
line-height: 16px; |
||||
padding: 10px; |
||||
border-radius: 3px; |
||||
background: rgba(255,255,255,0.9); |
||||
color: #000; |
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4); |
||||
-moz-box-shadow: 0 1px 5px rgba(0,0,0,0.4); |
||||
border:1px solid rgba(200,200,200,0.85); |
||||
text-align:center; |
||||
} |
||||
#tooltip[data-v-6039702a] { |
||||
text-align:center; |
||||
z-index: 1000; |
||||
position: absolute; |
||||
display: block; |
||||
} |
||||
#tooltip .description[data-v-6039702a] { |
||||
color:#666; |
||||
font-size: 11px; |
||||
text-align:center; |
||||
font-style:italic; |
||||
} |
||||
#tooltip .title[data-v-6039702a] { |
||||
text-align: left; |
||||
font-size: 13px; |
||||
text-align:center; |
||||
} |
||||
|
||||
|
||||
.holder[data-v-28f41ffe] { |
||||
width: 500px; |
||||
margin: auto; |
||||
} |
||||
.menu ul[data-v-28f41ffe] { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
.menu li[data-v-28f41ffe] { |
||||
text-align: left; |
||||
} |
||||
|
||||
.menu[data-v-37ada400] { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
.menu li[data-v-37ada400] { |
||||
text-align: left; |
||||
display: inline-block; |
||||
text-align: left; |
||||
margin: 0px; |
||||
margin-right: 10px; |
||||
} |
||||
.menu li a[data-v-37ada400] { |
||||
text-decoration: none; |
||||
} |
||||
.menu li a.active[data-v-37ada400] { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
h1[data-v-417810ac], h2[data-v-417810ac] { |
||||
font-weight: normal; |
||||
} |
||||
ul[data-v-417810ac] { |
||||
/*list-style-type: none;*/ |
||||
padding: 0; |
||||
margin: auto; |
||||
width: 300px; |
||||
} |
||||
li[data-v-417810ac] { |
||||
/*display: inline-block;*/ |
||||
margin: 0 0px; |
||||
list-style: decimal |
||||
} |
||||
a[data-v-417810ac] { |
||||
color: blue; |
||||
display: block; |
||||
text-decoration: none; |
||||
text-align: left; |
||||
} |
||||
a[data-v-417810ac]:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
/*# sourceMappingURL=app.ea478ad0f98c40581c472cf6cea74c24.css.map*/ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +0,0 @@
|
||||
!function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(t,c,i){for(var u,a,f,s=0,l=[];s<t.length;s++)a=t[s],o[a]&&l.push(o[a][0]),o[a]=0;for(u in c)Object.prototype.hasOwnProperty.call(c,u)&&(e[u]=c[u]);for(n&&n(t,c,i);l.length;)l.shift()();if(i)for(s=0;s<i.length;s++)f=r(r.s=i[s]);return f};var t={},o={2:0};r.e=function(e){function n(){c.onerror=c.onload=null,clearTimeout(i);var r=o[e];0!==r&&(r&&r[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}if(0===o[e])return Promise.resolve();if(o[e])return o[e][2];var t=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.timeout=12e4,r.nc&&c.setAttribute("nonce",r.nc),c.src=r.p+"static/js/"+e+"."+{0:"03b56a03b17565331709",1:"bb478689be3640ebf141"}[e]+".js";var i=setTimeout(n,12e4);c.onerror=c.onload=n;var u=new Promise(function(r,n){o[e]=[r,n]});return o[e][2]=u,t.appendChild(c),u},r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="/",r.oe=function(e){throw console.error(e),e}}([]); |
||||
//# sourceMappingURL=manifest.0d9440aa0954c24a67c3.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue