@@ -8,8 +8,10 @@ | |||
"lint": "vue-cli-service lint" | |||
}, | |||
"dependencies": { | |||
"apexcharts": "^3.13.0", | |||
"core-js": "^3.4.3", | |||
"vue": "^2.6.10", | |||
"vue-apexcharts": "^1.5.1", | |||
"vue-router": "^3.1.3", | |||
"vuetify": "^2.1.15" | |||
}, | |||
@@ -78,6 +78,10 @@ export default { | |||
{ | |||
title: "Retro Stats", | |||
href: "https://network.dero.io" | |||
}, | |||
{ | |||
title: "Stats", | |||
to: "/stats" | |||
} | |||
], | |||
menu: [ | |||
@@ -91,6 +95,8 @@ export default { | |||
mounted() { | |||
if (localStorage.theme) { | |||
this.$vuetify.theme.dark = localStorage.theme == "dark" | |||
} else { | |||
this.$vuetify.theme.dark = true | |||
} | |||
}, | |||
methods: { /* eslint-disable no-console */ | |||
@@ -0,0 +1,217 @@ | |||
/* eslint-disable no-console */ | |||
import * as explorer from './explorer' | |||
const cache = { | |||
depth: 0, | |||
info: {}, | |||
blocks: [] | |||
} | |||
export async function init(depth = 100, n = 1000) | |||
{ | |||
let info = await explorer.getInfo() | |||
cache.info = info | |||
cache.depth = depth | |||
cache.n = n | |||
cache.blocks = await explorer.getBlocks(cache.info.topoheight, cache.depth, cache.n) | |||
} | |||
function createChart(title, name, categories = [], data = []) | |||
{ | |||
const options = { | |||
chart: { | |||
height: 500, | |||
type: 'line', | |||
background: '#424242', | |||
toolbar: { | |||
show: false | |||
}, | |||
shadow: { | |||
enabled: false, | |||
color: 'red', | |||
top: 3, | |||
left: 2, | |||
blur: 3, | |||
opacity: 1 | |||
}, | |||
}, | |||
theme: { | |||
mode: 'dark', | |||
palette: 'palette1', | |||
monochrome: { | |||
enabled: false, | |||
color: '#255aee', | |||
shadeTo: 'dark', | |||
shadeIntensity: 0.65 | |||
}, | |||
}, | |||
stroke: { | |||
width: 7, | |||
curve: 'smooth' | |||
}, | |||
xaxis: { | |||
type: 'string', | |||
categories: [], | |||
labels: { | |||
show: false | |||
} | |||
}, | |||
title: { | |||
text: 'No Text', | |||
align: 'center', | |||
style: { | |||
fontSize: "24px" | |||
} | |||
}, | |||
fill: { | |||
type: 'gradient', | |||
gradient: { | |||
shade: 'dark', | |||
gradientToColors: ['#FDD835'], | |||
shadeIntensity: 1, | |||
type: 'horizontal', | |||
opacityFrom: 1, | |||
opacityTo: 1, | |||
stops: [0, 100, 100, 100] | |||
}, | |||
}, | |||
markers: { | |||
size: 4, | |||
opacity: 0.9, | |||
colors: ["#FFA41B"], | |||
strokeColor: "#fff", | |||
strokeWidth: 2, | |||
hover: { | |||
size: 7, | |||
} | |||
} | |||
} | |||
options.title.text = title | |||
options.xaxis.categories = categories | |||
return { | |||
datas: [{ | |||
name: name, | |||
data: data | |||
}], | |||
options: options | |||
} | |||
} | |||
/* | |||
export function networkChart() | |||
{ | |||
const categories = [] | |||
const datas = [] | |||
let val = getNetwork() | |||
let diff = [] | |||
let hashrate = [] | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
categories.push(explorer.formatSupply(val[i].height)) | |||
diff.push(val[i].difficulty) | |||
hashrate.push(val[i].hashrate) | |||
} | |||
datas.push({name: "Difficulty", data: diff}, {name: "MH/s", data: hashrate}) | |||
return createChart("Network Chart", "", categories, datas) | |||
}*/ | |||
export function difficultyChart() | |||
{ | |||
const categories = [] | |||
const data = [] | |||
let val = getDifficulty() | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
categories.push(explorer.formatSupply(val[i].height)) | |||
data.push(val[i].difficulty) | |||
} | |||
return createChart("Difficulty Chart", "Difficulty", categories, data) | |||
} | |||
export function rewardChart() | |||
{ | |||
const categories = [] | |||
const data = [] | |||
let val = getRewards() | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
categories.push(explorer.formatSupply(val[i].height)) | |||
data.push(val[i].reward) | |||
} | |||
return createChart("Reward Chart", "Reward", categories, data) | |||
} | |||
export function hashrateChart() | |||
{ | |||
const categories = [] | |||
const data = [] | |||
let val = getHashrates() | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
categories.push(explorer.formatSupply(val[i].height)) | |||
data.push(val[i].hashrate) | |||
} | |||
return createChart("Hashrate Chart", "MH/s", categories, data) | |||
} | |||
function getDifficulty() | |||
{ | |||
const array = [] | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
let block = cache.blocks[i] | |||
array.push({height: block.height, difficulty: block.difficulty}) | |||
} | |||
return array | |||
} | |||
function getHashrates() | |||
{ | |||
const array = [] | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
let block = cache.blocks[i] | |||
array.push({height: block.height, hashrate: (block.difficulty/(cache.info.target*1000*1000)).toFixed(2)}) | |||
} | |||
return array | |||
} | |||
function getRewards() | |||
{ | |||
const array = [] | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
let block = cache.blocks[i] | |||
array.push({height: block.height, reward: block.reward}) | |||
} | |||
return array | |||
} | |||
/* | |||
function getNetwork() | |||
{ | |||
const array = [] | |||
for (let i = 0; i < cache.depth; i++) | |||
{ | |||
let block = cache.blocks[i] | |||
array.push({height: block.height, difficulty: block.difficulty, hashrate: (block.difficulty/(cache.info.target*1000*1000)).toFixed(2)}) | |||
} | |||
return array | |||
}*/ |
@@ -4,7 +4,7 @@ | |||
<v-btn v-on="on" text>{{ name }}</v-btn> | |||
</template> | |||
<v-list dark> | |||
<v-list-item v-for="(item, index) in items" :key="index" :href="item.href"> | |||
<v-list-item v-for="(item, index) in items" :key="index" :href="item.href" :to="item.to"> | |||
<v-list-item-title >{{ item.title }}</v-list-item-title> | |||
</v-list-item> | |||
</v-list> | |||
@@ -1,5 +1,5 @@ | |||
/* eslint-disable no-console */ | |||
var daemon = 'https://wallet.dero.io' | |||
const daemon = 'https://wallet.dero.io' | |||
export function blockDate(timestamp) { | |||
let date = new Date(timestamp * 1000); | |||
@@ -21,6 +21,23 @@ export function getInfo() | |||
return postData("get_info") | |||
} | |||
export async function getBlocks(pos, depth, n = 1) | |||
{ | |||
const array = [] | |||
for (let i = 0; i < depth; i++) | |||
{ | |||
let block = await loadBlock(pos - ((depth - i) * n)) | |||
if (block) { | |||
array.push({ | |||
height: block.block_header.topoheight, | |||
difficulty: block.block_header.difficulty, | |||
reward: (block.block_header.reward / 1000000000000).toFixed(4) | |||
}) | |||
} | |||
} | |||
return array | |||
} | |||
export function loadTxs(txsHashes = []) | |||
{ | |||
const body = { | |||
@@ -3,13 +3,15 @@ import Vue from 'vue'; | |||
import Index from './views/Index.vue' | |||
import Block from './views/Block.vue' | |||
import Tx from './views/Tx.vue' | |||
import Stats from './views/Stats.vue' | |||
Vue.use(VueRouter) | |||
const routes = [ | |||
{ path: '/', component: Index }, | |||
{ path: '/block/:id', component: Block }, | |||
{ path: '/tx/:hash', component: Tx } | |||
{ path: '/tx/:hash', component: Tx }, | |||
{ path: '/stats', component: Stats } | |||
]; | |||
export default new VueRouter({ | |||
@@ -0,0 +1,39 @@ | |||
<template> | |||
<div v-if="ready" id="stats"> | |||
<div id="charts"> | |||
<apexchart class="chart" type="line" :options="networkChart.options" :series="networkChart.datas"></apexchart> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import VueApexCharts from 'vue-apexcharts' | |||
import * as chart from '../charts' | |||
export default { | |||
components: { | |||
apexchart: VueApexCharts, | |||
}, | |||
data() { | |||
return { | |||
networkChart: {}, | |||
ready: false | |||
} | |||
}, | |||
async mounted() { | |||
await chart.init() | |||
this.networkChart = chart.hashrateChart() | |||
this.ready = true | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
#charts { | |||
margin-top: 5%; | |||
margin-left: 15%; | |||
margin-right: 15%; | |||
margin-bottom: 5%; | |||
} | |||
.chart { | |||
} | |||
</style> |
@@ -1329,6 +1329,18 @@ anymatch@^2.0.0: | |||
micromatch "^3.1.4" | |||
normalize-path "^2.1.1" | |||
apexcharts@^3.13.0: | |||
version "3.13.0" | |||
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.13.0.tgz#e74c0edfe83164987b409d82138aa8ab6e320a02" | |||
integrity sha512-yXQ6HZHBu34nQsowx1dk861jK1kg2q+gpU8VE3J2g32FfQvH9QKuppigkdmu8JysjOZB4YPIEh3vUuUVXouhkA== | |||
dependencies: | |||
svg.draggable.js "^2.2.2" | |||
svg.easing.js "^2.0.0" | |||
svg.filter.js "^2.0.2" | |||
svg.pathmorphing.js "^0.1.3" | |||
svg.resize.js "^1.4.3" | |||
svg.select.js "^2.1.2" | |||
aproba@^1.1.1: | |||
version "1.2.0" | |||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" | |||
@@ -7235,6 +7247,54 @@ svg-tags@^1.0.0: | |||
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" | |||
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= | |||
svg.draggable.js@^2.2.2: | |||
version "2.2.2" | |||
resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" | |||
integrity sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw== | |||
dependencies: | |||
svg.js "^2.0.1" | |||
svg.easing.js@^2.0.0: | |||
version "2.0.0" | |||
resolved "https://registry.yarnpkg.com/svg.easing.js/-/svg.easing.js-2.0.0.tgz#8aa9946b0a8e27857a5c40a10eba4091e5691f12" | |||
integrity sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI= | |||
dependencies: | |||
svg.js ">=2.3.x" | |||
svg.filter.js@^2.0.2: | |||
version "2.0.2" | |||
resolved "https://registry.yarnpkg.com/svg.filter.js/-/svg.filter.js-2.0.2.tgz#91008e151389dd9230779fcbe6e2c9a362d1c203" | |||
integrity sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM= | |||
dependencies: | |||
svg.js "^2.2.5" | |||
svg.js@>=2.3.x, svg.js@^2.0.1, svg.js@^2.2.5, svg.js@^2.4.0, svg.js@^2.6.5: | |||
version "2.7.1" | |||
resolved "https://registry.yarnpkg.com/svg.js/-/svg.js-2.7.1.tgz#eb977ed4737001eab859949b4a398ee1bb79948d" | |||
integrity sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA== | |||
svg.pathmorphing.js@^0.1.3: | |||
version "0.1.3" | |||
resolved "https://registry.yarnpkg.com/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz#c25718a1cc7c36e852ecabc380e758ac09bb2b65" | |||
integrity sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww== | |||
dependencies: | |||
svg.js "^2.4.0" | |||
svg.resize.js@^1.4.3: | |||
version "1.4.3" | |||
resolved "https://registry.yarnpkg.com/svg.resize.js/-/svg.resize.js-1.4.3.tgz#885abd248e0cd205b36b973c4b578b9a36f23332" | |||
integrity sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw== | |||
dependencies: | |||
svg.js "^2.6.5" | |||
svg.select.js "^2.1.2" | |||
svg.select.js@^2.1.2: | |||
version "2.1.2" | |||
resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-2.1.2.tgz#e41ce13b1acff43a7441f9f8be87a2319c87be73" | |||
integrity sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ== | |||
dependencies: | |||
svg.js "^2.2.5" | |||
svgo@^1.0.0: | |||
version "1.3.2" | |||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" | |||
@@ -7707,6 +7767,11 @@ vm-browserify@^1.0.1: | |||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" | |||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== | |||
vue-apexcharts@^1.5.1: | |||
version "1.5.1" | |||
resolved "https://registry.yarnpkg.com/vue-apexcharts/-/vue-apexcharts-1.5.1.tgz#f235d3c8047690f598864b70bd389081efff7576" | |||
integrity sha512-faMfIj7g4MEceWjh5Aux7NfEdJYiSvMK6ml6UA2oeQH444kU4z532zR8P6AvCj0x6LzV2fgv2POzt0poMaoIjg== | |||
vue-eslint-parser@^5.0.0: | |||
version "5.0.0" | |||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1" | |||