Initial commit

This commit is contained in:
simon987
2019-04-07 11:25:50 -04:00
commit 797fae9ec1
32 changed files with 27663 additions and 0 deletions

20
ui/music_graph/.babelrc Normal file
View File

@@ -0,0 +1,20 @@
{
"presets": [
[
"env",
{
"modules": false
}
]
],
"plugins": [
"lodash",
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-default"
}
]
]
}

View File

@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

View File

@@ -0,0 +1,2 @@
build/*.js
config/*.js

View File

@@ -0,0 +1,53 @@
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
},
extends: 'airbnb-base',
// required to lint *.vue files
plugins: [
'html'
],
// check if imports actually resolve
'settings': {
'import/resolver': {
'webpack': {
'config': 'build/webpack.base.js'
}
}
},
// add your custom rules here
'rules': {
// Indent with 4 spaces
"indent": ["error", 4],
"no-param-reassign": 0,
"no-underscore-dangle": 0,
// don't require .vue extension when importing
'import/extensions': ['error', 'always', {
'js': 'never',
'vue': 'never'
}],
// allow optionalDependencies
'import/no-extraneous-dependencies': ['error', {
'optionalDependencies': ['test/unit/index.js']
}],
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
},
"globals": {
"describe": true,
"it": true,
"expect": true,
"window": true,
"document": true,
"__DEV__": true,
"__PROD__": true,
"__APP_MODE__": ""
},
};

View File

@@ -0,0 +1,10 @@
const API_URL = '//app.example.com/api';
const API_VERSION = '2.0';
const BASE_URL = `${API_URL}/${API_VERSION}`;
exports.getURL = url => BASE_URL + url;
module.exports = {
appName: 'Some App Specific Mode',
otherAPI: exports.getURL('/something/')
};

View File

@@ -0,0 +1,13 @@
const API_URL = '//app.example.com/api';
const API_VERSION = '1.0';
const BASE_URL = `${API_URL}/${API_VERSION}`;
exports.getURL = url => BASE_URL + url;
module.exports = {
appName: 'Default App',
debug: false,
sessionName: 'session_id',
credential: 'same-origin',
exampleAPI: exports.getURL('/thing/')
};

View File

@@ -0,0 +1,26 @@
const path = require('path');
const API_URL = '//localhost:7000/api';
const API_VERSION = '1.0';
const BASE_URL = `${API_URL}/${API_VERSION}`;
exports.getURL = url => BASE_URL + url;
module.exports = {
appName: 'Dev App',
debug: true,
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'assets',
assetsPublicPath: '/',
// 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,
};

View File

@@ -0,0 +1,25 @@
const path = require('path');
const API_URL = '//app.production.com/api';
const API_VERSION = '2.0';
const BASE_URL = `${API_URL}/${API_VERSION}`;
exports.getURL = url => BASE_URL + url;
module.exports = {
appName: 'Prod App',
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'assets',
assetsPublicPath: '/',
// 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,
};

View File

@@ -0,0 +1,24 @@
const merge = require('webpack-merge');
const DEV = 'development';
const PROD = 'production';
const env = process.env.NODE_ENV || DEV;
const isDev = env === DEV;
const isProd = env === PROD;
const appMode = process.env.NODE_APP_MODE || 'app';
const defaults = {
env,
isProd,
isDev,
appMode,
};
const baseConfig = require('./config.base');
const envConfig = require(`./config.${env}`);
const appConfig = require(`./config.${appMode}`);
const config = merge(defaults, baseConfig, envConfig, appConfig);
module.exports = config;

12
ui/music_graph/index.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>music_graph</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

10946
ui/music_graph/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
{
"name": "music_graph",
"description": "wip",
"version": "1.0.0",
"author": "simon987 <>",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development NODE_APP_MODE=app webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production NODE_APP_MODE=app webpack --progress --hide-modules",
"lint": "eslint --ext .js,.vue src test/unit/specs"
},
"dependencies": {
"d3": "^5.9.2",
"d3-force": "^2.0.1",
"vue": "^2.4.2",
"vue-router": "^2.7.0"
},
"devDependencies": {
"axios": "^0.16.2",
"babel-core": "^6.25.0",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.1.1",
"babel-preset-env": "^1.6.0",
"compression-webpack-plugin": "^1.0.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.4",
"eslint": "^4.4.1",
"eslint-loader": "^1.9.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-plugin-html": "^3.2.0",
"eslint-config-airbnb-base": "^11.3.1",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-plugin-import": "^2.7.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"element-ui": "^1.4.2",
"babel-plugin-component": "^0.10.0",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"lodash": "^4.17.4",
"babel-plugin-lodash": "^3.2.11",
"lodash-webpack-plugin": "^0.11.4",
"node-sass": "^4.5.3",
"optimize-css-assets-webpack-plugin": "^3.0.0",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"url-loader": "^0.5.9",
"vue-loader": "^13.0.4",
"vue-template-compiler": "^2.4.2",
"webpack": "^3.5.4",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.7.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

View File

@@ -0,0 +1,16 @@
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app',
};
</script>
<style>
#app {
}
</style>

View File

@@ -0,0 +1,176 @@
<template>
<div class='hello'>
</div>
</template>
<script>
import * as d3 from 'd3';
function getNodeType(labels) {
if (labels.find(l => l === 'Tag')) {
return 'Tag';
} else if (labels.find(l => l === 'Group')) {
return 'Group';
} else if (labels.find(l => l === 'Artist')) {
return 'Artist';
}
return undefined;
}
let data = {};
d3.json('../static/data.json')
.then((r) => {
data = r;
const links = data.map(row => ({
source: row._fields[1].start.low,
target: row._fields[1].end.low,
weight: row._fields[1].properties.weight.low,
}));
const nodes = [];
function addNode(node) {
if (nodes.find(n => n.id === node.id)) {
return;
}
nodes.push(node);
}
data.forEach((row) => {
addNode({
id: row._fields[0].identity.low,
name: row._fields[0].properties.name,
listeners: row._fields[0].properties.listeners.low,
type: getNodeType(row._fields[0].labels),
});
addNode({
id: row._fields[2].identity.low,
name: row._fields[2].properties.name,
type: 'Tag',
});
});
function getRadius(node) {
if (node.type === 'Tag') {
return 10;
}
return Math.max(Math.sqrt(node.listeners / 5000), 15);
}
function getColor(node) {
switch (node.type) {
case 'Tag':
return '#e0e0e0';
case 'Artist':
return '#42c3f7';
case 'Group':
return '#00a5e9';
default:
return '#DEADFB';
}
}
const width = window.innerWidth - 5;
const height = window.innerHeight - 5;
// ??
const simulation = d3.forceSimulation(nodes)
.force('link', d3.forceLink(links).id(d => d.id))
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2))
;
let container;
function zoomed() {
container.attr('transform', d3.event.transform);
}
function nodeZoomed() {
// TODO
}
function dragStarted(d) {
if (!d3.event.active) {
simulation.alphaTarget(0.3).restart();
}
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragEnded(d) {
if (!d3.event.active) {
simulation.alphaTarget(0);
}
d.fx = null;
d.fy = null;
}
const svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
svg.append('rect')
.attr('width', width)
.attr('height', height)
.style('pointer-events', 'all')
.style('fill', 'none')
.call(d3.zoom()
.scaleExtent([1 / 3, 5])
.on('zoom', zoomed));
document.body.setAttribute('style', 'background: #E7EDEB');
container = svg.append('g');
const link = container.append('g')
.attr('stroke', '#003a6b')
.selectAll('line')
.data(links)
.join('line')
.attr('stroke-opacity', rel => rel.weight / 15)
.attr('stroke-width', rel => Math.sqrt(rel.weight) * 0.6);
const node = container.append('g')
.attr('stroke', '#ffffff')
.attr('stroke-width', 1.5)
.selectAll('circle')
.data(nodes)
.join('circle')
.attr('r', d => getRadius(d))
.attr('fill', d => getColor(d))
.call(d3.drag()
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded))
.on('wheel', nodeZoomed);
node.append('title')
.text(d => `${d.name} ${d.id}`);
simulation.on('tick', () => {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
node
.attr('cx', d => d.x)
.attr('cy', d => d.y);
});
});
export default {
name: 'hello',
data() {
return {
msg: 'Welcome to Your Vue.js App',
};
},
};
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,13 @@
import Vue from 'vue';
import 'element-ui/lib/theme-default/index.css';
import App from './App';
import router from './router';
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App),
});

View File

@@ -0,0 +1,15 @@
import Vue from 'vue';
import Router from 'vue-router';
import Hello from '../components/Hello';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello,
},
],
});

View File

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
/* eslint-disable */
const webpackMerge = require('webpack-merge');
module.exports = () => {
const env = process.env.NODE_ENV;
const baseConfig = require('./build/webpack.base');
const envConfig = require(`./build/webpack.${env}`);
return webpackMerge(baseConfig, envConfig);
};