mirror of
https://github.com/simon987/music-graph-ui.git
synced 2025-04-18 17:46:42 +00:00
Add loading indicator
This commit is contained in:
parent
f2760d8f3e
commit
3ab1e90638
@ -1,6 +1,5 @@
|
|||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
import icons from './icons'
|
import icons from './icons'
|
||||||
import {MusicGraphApi} from './MusicGraphApi'
|
|
||||||
import {fitCaptionIntoCircle} from './graphGeometry'
|
import {fitCaptionIntoCircle} from './graphGeometry'
|
||||||
|
|
||||||
// TODO: export somewhere else
|
// TODO: export somewhere else
|
||||||
@ -22,13 +21,13 @@ export function MusicGraph(data) {
|
|||||||
const width = window.innerWidth - 7
|
const width = window.innerWidth - 7
|
||||||
const height = window.innerHeight - 7
|
const height = window.innerHeight - 7
|
||||||
this._data = data
|
this._data = data
|
||||||
|
this.api = this._data.api
|
||||||
|
|
||||||
this.nodeById = new Map()
|
this.nodeById = new Map()
|
||||||
this.expandedNodes = new Set()
|
this.expandedNodes = new Set()
|
||||||
this.nodes = []
|
this.nodes = []
|
||||||
this.links = []
|
this.links = []
|
||||||
this._originSet = false
|
this._originSet = false
|
||||||
this.api = new MusicGraphApi()
|
|
||||||
|
|
||||||
this.simulation = d3.forceSimulation()
|
this.simulation = d3.forceSimulation()
|
||||||
.force('charge', d3.forceManyBody())
|
.force('charge', d3.forceManyBody())
|
||||||
@ -43,7 +42,9 @@ export function MusicGraph(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.dismiss = () => {
|
this.dismiss = () => {
|
||||||
this.menu.remove()
|
if (this.menu) {
|
||||||
|
this.menu.remove()
|
||||||
|
}
|
||||||
const menuNode = this.nodes.find(d => d.menu)
|
const menuNode = this.nodes.find(d => d.menu)
|
||||||
if (menuNode !== undefined) {
|
if (menuNode !== undefined) {
|
||||||
menuNode.menu = null
|
menuNode.menu = null
|
||||||
|
@ -52,22 +52,33 @@ const nodeUtils = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MusicGraphApi() {
|
export function MusicGraphApi(data) {
|
||||||
this.url = window.location.protocol + '//' + window.location.hostname + '/api'
|
this.url = window.location.protocol + '//' + window.location.hostname + '/api'
|
||||||
|
this._data = data
|
||||||
|
|
||||||
|
let loadWrapper = (fn) => {
|
||||||
|
return (...args) => {
|
||||||
|
this._data.loading = true
|
||||||
|
return fn(...args).then(x => {
|
||||||
|
this._data.loading = false
|
||||||
|
return x
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.resolveCoverUrl = function (mbid) {
|
this.resolveCoverUrl = function (mbid) {
|
||||||
return this.url + '/cover/' + mbid
|
return this.url + '/cover/' + mbid
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getArtistDetails = function (mbid) {
|
this.getArtistDetails = loadWrapper((mbid) => {
|
||||||
return d3.json(this.url + '/artist/details/' + mbid)
|
return d3.json(this.url + '/artist/details/' + mbid)
|
||||||
}
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Works in both directions
|
* Works in both directions
|
||||||
* @returns {Promise<{newNodes: *, relations: *} | never>}
|
* @returns {Promise<{newNodes: *, relations: *} | never>}
|
||||||
*/
|
*/
|
||||||
this.getGroupMembers = function (mbid, originId) {
|
this.getGroupMembers = loadWrapper((mbid, originId) => {
|
||||||
return d3.json(this.url + '/artist/members/' + mbid)
|
return d3.json(this.url + '/artist/members/' + mbid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
return {
|
return {
|
||||||
@ -81,29 +92,9 @@ export function MusicGraphApi() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getArtistReleases = function (mbid, originId) {
|
this.getArtistLabels = loadWrapper((mbid, originId) => {
|
||||||
return d3.json(this.url + '/artist/details/' + mbid)
|
|
||||||
.then((r) => {
|
|
||||||
const newNodes = r.releases
|
|
||||||
.map(nodeUtils.fromRawDict)
|
|
||||||
.filter(release => release.type === 'Album')
|
|
||||||
|
|
||||||
return {
|
|
||||||
newNodes: newNodes,
|
|
||||||
relations: newNodes.map(t => {
|
|
||||||
return {
|
|
||||||
source: originId,
|
|
||||||
target: t.id,
|
|
||||||
weight: 0.8
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getArtistLabels = function (mbid, originId) {
|
|
||||||
return d3.json(this.url + '/artist/details/' + mbid)
|
return d3.json(this.url + '/artist/details/' + mbid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const newNodes = r.labels
|
const newNodes = r.labels
|
||||||
@ -124,25 +115,25 @@ export function MusicGraphApi() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this._filterTags = function (tags) {
|
this._filterTags = loadWrapper((tags) => {
|
||||||
if (ONLY_GENRE_TAGS) {
|
if (ONLY_GENRE_TAGS) {
|
||||||
return tags.filter(tag => genres.has(tag.name))
|
return tags.filter(tag => genres.has(tag.name))
|
||||||
} else if (IGNORE_DATES_TAG) {
|
} else if (IGNORE_DATES_TAG) {
|
||||||
return tags.filter(tag => isNaN(tag.name) && isNaN(tag.name.slice(0, -1)))
|
return tags.filter(tag => isNaN(tag.name) && isNaN(tag.name.slice(0, -1)))
|
||||||
}
|
}
|
||||||
return tags
|
return tags
|
||||||
}
|
})
|
||||||
|
|
||||||
this._addTagLabel = function (objects) {
|
this._addTagLabel = loadWrapper((objects) => {
|
||||||
return objects.map(tag => {
|
return objects.map(tag => {
|
||||||
tag.labels = ['Tag']
|
tag.labels = ['Tag']
|
||||||
return tag
|
return tag
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getArtistTags = function (mbid, originId) {
|
this.getArtistTags = loadWrapper((mbid, originId) => {
|
||||||
return d3.json(this.url + '/artist/details/' + mbid)
|
return d3.json(this.url + '/artist/details/' + mbid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const tags = this._filterTags(r.tags)
|
const tags = this._filterTags(r.tags)
|
||||||
@ -158,9 +149,9 @@ export function MusicGraphApi() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getRelatedTags = function (tagId) {
|
this.getRelatedTags = loadWrapper((tagId) => {
|
||||||
return d3.json(this.url + '/tag/tag/' + tagId)
|
return d3.json(this.url + '/tag/tag/' + tagId)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const tags = this._filterTags(r.tags)
|
const tags = this._filterTags(r.tags)
|
||||||
@ -182,9 +173,9 @@ export function MusicGraphApi() {
|
|||||||
relations: directedRelations
|
relations: directedRelations
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getRelatedByMbid = function (mbid) {
|
this.getRelatedByMbid = loadWrapper((mbid) => {
|
||||||
return d3.json(this.url + '/artist/related/' + mbid)
|
return d3.json(this.url + '/artist/related/' + mbid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
let node = nodeUtils.fromRawDict(r.artists.find(a => a.mbid === mbid))
|
let node = nodeUtils.fromRawDict(r.artists.find(a => a.mbid === mbid))
|
||||||
@ -207,9 +198,9 @@ export function MusicGraphApi() {
|
|||||||
relations: directedRelations
|
relations: directedRelations
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getRelatedByTag = function (tagid) {
|
this.getRelatedByTag = loadWrapper((tagid) => {
|
||||||
return d3.json(this.url + '/tag/related/' + tagid)
|
return d3.json(this.url + '/tag/related/' + tagid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
return {
|
return {
|
||||||
@ -229,9 +220,9 @@ export function MusicGraphApi() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.getReleaseDetails = function (mbid, originId) {
|
this.getReleaseDetails = loadWrapper((mbid, originId) => {
|
||||||
return d3.json(this.url + '/release/details/' + mbid)
|
return d3.json(this.url + '/release/details/' + mbid)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const tags = this._filterTags(r.tags)
|
const tags = this._filterTags(r.tags)
|
||||||
@ -247,12 +238,13 @@ export function MusicGraphApi() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
this.autoComplete = function (prefix) {
|
this.autoComplete = loadWrapper((prefix) => {
|
||||||
prefix = prefix.replace(/[^\w.\-!?& ]/g, '_').toUpperCase()
|
prefix = prefix
|
||||||
prefix = prefix.replace(/ /g, '+')
|
.replace(/[^\w.\-!?& ]/g, '_').toUpperCase()
|
||||||
|
.replace(/ /g, '+')
|
||||||
|
|
||||||
return d3.json(this.url + '/autocomplete/' + prefix)
|
return d3.json(this.url + '/autocomplete/' + prefix)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {MusicGraphApi} from '../MusicGraphApi'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AlbumCarousel',
|
name: 'AlbumCarousel',
|
||||||
props: ['releases', 'interval', 'alone'],
|
props: ['releases', 'interval', 'alone', 'api'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
api: new MusicGraphApi(),
|
|
||||||
current: '',
|
current: '',
|
||||||
index: 0
|
index: 0
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<AlbumCarousel
|
<AlbumCarousel
|
||||||
style="float: right"
|
style="float: right"
|
||||||
:releases="artistInfo.releases"
|
:releases="artistInfo.releases"
|
||||||
|
:api="api"
|
||||||
interval="1250"/>
|
interval="1250"/>
|
||||||
<div>
|
<div>
|
||||||
<p v-if="artistInfo.comment!==null"
|
<p v-if="artistInfo.comment!==null"
|
||||||
@ -31,13 +32,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AlbumCarousel from './AlbumCarousel'
|
import AlbumCarousel from './AlbumCarousel'
|
||||||
import {MusicGraphApi} from '../MusicGraphApi'
|
|
||||||
import {genres} from '../genres'
|
import {genres} from '../genres'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ArtistInfo',
|
name: 'ArtistInfo',
|
||||||
components: {AlbumCarousel},
|
components: {AlbumCarousel},
|
||||||
props: ['artist'],
|
props: ['artist', 'api'],
|
||||||
watch: {
|
watch: {
|
||||||
artist: function (a) {
|
artist: function (a) {
|
||||||
if (a !== undefined) {
|
if (a !== undefined) {
|
||||||
@ -49,8 +49,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
artistInfo: {
|
artistInfo: {
|
||||||
releases: []
|
releases: []
|
||||||
},
|
}
|
||||||
api: new MusicGraphApi()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div id="mm"></div>
|
<div id="mm"></div>
|
||||||
<InputBar v-on:addArtist="onAddArtist($event)" v-on:addTag="onAddTag($event)"></InputBar>
|
<InputBar
|
||||||
|
v-on:addArtist="onAddArtist($event)"
|
||||||
|
v-on:addTag="onAddTag($event)"
|
||||||
|
:api="api"
|
||||||
|
></InputBar>
|
||||||
<ArtistInfo
|
<ArtistInfo
|
||||||
v-bind:artist="hoverArtist"
|
v-bind:artist="hoverArtist"
|
||||||
v-on:addTag="onAddTag($event)"
|
v-on:addTag="onAddTag($event)"
|
||||||
|
:api="api"
|
||||||
/>
|
/>
|
||||||
<canvas id="textMeasurementCanvas"></canvas>
|
<canvas id="textMeasurementCanvas"></canvas>
|
||||||
<Watermark text="music-graph v1.0"/>
|
<Watermark text="music-graph v1.0"/>
|
||||||
|
<LoadingIndicator :loading="loading"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -16,14 +22,18 @@ import ArtistInfo from './ArtistInfo'
|
|||||||
import Watermark from './Watermark'
|
import Watermark from './Watermark'
|
||||||
import {MusicGraph} from '../MusicGraph'
|
import {MusicGraph} from '../MusicGraph'
|
||||||
import InputBar from './InputBar'
|
import InputBar from './InputBar'
|
||||||
|
import LoadingIndicator from './LoadingIndicator'
|
||||||
|
import {MusicGraphApi} from '../MusicGraphApi'
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
hoverArtist: undefined,
|
hoverArtist: undefined,
|
||||||
mm: undefined
|
mm: undefined,
|
||||||
|
api: undefined,
|
||||||
|
loading: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {InputBar, ArtistInfo, Watermark},
|
components: {LoadingIndicator, InputBar, ArtistInfo, Watermark},
|
||||||
data() {
|
data() {
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
@ -36,6 +46,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.api = new MusicGraphApi(data)
|
||||||
this.mm = new MusicGraph(data)
|
this.mm = new MusicGraph(data)
|
||||||
|
|
||||||
this.$notify({
|
this.$notify({
|
||||||
|
@ -20,16 +20,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {MusicGraphApi} from '../MusicGraphApi'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InputBar',
|
name: 'InputBar',
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
query: '',
|
query: ''
|
||||||
api: new MusicGraphApi()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
props: ['api'],
|
||||||
methods: {
|
methods: {
|
||||||
onSubmit: function (line) {
|
onSubmit: function (line) {
|
||||||
if (line.type === 'artist') {
|
if (line.type === 'artist') {
|
||||||
|
26
music_graph/src/components/LoadingIndicator.vue
Normal file
26
music_graph/src/components/LoadingIndicator.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<el-icon class="el-icon-loading" :class="{hidden: !loading}" id="loading"></el-icon>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LoadingIndicator',
|
||||||
|
props: ['loading']
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading {
|
||||||
|
position: fixed;
|
||||||
|
top: calc(100% - 90px);
|
||||||
|
left: 75px;
|
||||||
|
pointer-events: none;
|
||||||
|
color: rgba(0, 0, 0, 0.67);
|
||||||
|
font-size: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user