Change main live canvas to act like a mempool

This commit is contained in:
Joshua Seigler 2019-04-08 04:34:52 -04:00
parent 5c9a82b87f
commit 66283fcfe2
4 changed files with 116 additions and 85 deletions

View file

@ -8,46 +8,43 @@ import { PSDENOMINATIONS, COLORS, PAINT } from './constants';
export default class App { export default class App {
constructor() { constructor() {
this.blockRefs = [];
this.mempoolRefs = [];
this.blockList = document.getElementById('blockList');
this.connectionStatus = document.getElementById('connectionStatus');
this.hero = document.getElementById('hero');
this.blockColors = ['000000'];
} }
async init() { async init() {
this.domRefList = [];
this.blockList = document.getElementById('blockList');
this.blockList.style.setProperty('--private-color', COLORS.private);
this.blockList.style.setProperty('--instant-color', COLORS.instant);
this.connectionStatus = document.getElementById('connectionStatus')
this.currentBlock = document.createElement('div');
this.currentBlock.className = 'block';
this.blockList.appendChild(this.currentBlock);
this.blockColors = ['000000'];
const block = (new URL(window.location)).searchParams.get('block'); const block = (new URL(window.location)).searchParams.get('block');
if (block != null) { // display one block if (block != null) { // display one block
this.currentBlock.classList.add('solo'); this.hero.classList.add('solo');
this.connectionStatus.className = 'is-loading'; this.connectionStatus.className = 'is-loading';
var txs = []; var txs = [];
var pages = 1; var pages = 1;
var prevHash = null; var prevHash = null;
const txListener = this.onTransactionBuilder(this.hero, false);
for (let i = 0; i < pages; ++i) { for (let i = 0; i < pages; ++i) {
await fetch(`https://insight.dash.org/insight-api/txs?block=${block}&pageNum=${i}`) await fetch(`https://insight.dash.org/insight-api/txs?block=${block}&pageNum=${i}`)
.then(resp => resp.json()) .then(resp => resp.json())
.then(thisBlockData => { .then(thisBlockData => {
// console.log({i, pages, prevHash, thisBlockData});
if (!prevHash && thisBlockData.txs.length > 0) { if (!prevHash && thisBlockData.txs.length > 0) {
return fetch('https://insight.dash.org/insight-api/block-index/'+(thisBlockData.txs[0].blockheight - 1)) return fetch('https://insight.dash.org/insight-api/block-index/'+(thisBlockData.txs[0].blockheight - 1))
.then(resp => resp.json()) .then(resp => resp.json())
.then(prevBlockData => { .then(prevBlockData => {
prevHash = prevBlockData.blockHash; prevHash = prevBlockData.blockHash;
this.blockColors = App.generateColors(prevHash); this.blockColors = App.generateColors(prevHash);
this.applyColors(this.hero);
pages = thisBlockData.pagesTotal; pages = thisBlockData.pagesTotal;
for (let j = 0; j < thisBlockData.txs.length; ++j) { for (let j = 0; j < thisBlockData.txs.length; ++j) {
this.onTransaction(thisBlockData.txs[j]); txListener(thisBlockData.txs[j]);
} }
}); });
} else { } else {
for (let j = 0; j < thisBlockData.txs.length; ++j) { for (let j = 0; j < thisBlockData.txs.length; ++j) {
this.onTransaction(thisBlockData.txs[j]); txListener(thisBlockData.txs[j]);
} }
} }
}); });
@ -58,6 +55,7 @@ export default class App {
.then(resp => resp.json()) .then(resp => resp.json())
.then(data => { .then(data => {
this.blockColors = App.generateColors(data.lastblockhash); this.blockColors = App.generateColors(data.lastblockhash);
this.applyColors(this.hero);
}); });
this.socket = io.connect("https://insight.dash.org:443/"); this.socket = io.connect("https://insight.dash.org:443/");
@ -66,7 +64,7 @@ export default class App {
// Join the room. // Join the room.
this.socket.emit('subscribe', 'inv'); this.socket.emit('subscribe', 'inv');
}) })
this.socket.on('tx', this.onTransaction.bind(this)); this.socket.on('tx', this.onTransactionBuilder(this.hero, true).bind(this));
this.socket.on('block', this.onBlock.bind(this)); this.socket.on('block', this.onBlock.bind(this));
this.socket.on('disconnect', () => { this.socket.on('disconnect', () => {
this.connectionStatus.className = 'is-disconnected'; this.connectionStatus.className = 'is-disconnected';
@ -78,48 +76,71 @@ export default class App {
} }
static generateColors(blockHash) { static generateColors(blockHash) {
// https://github.com/c0bra/color-scheme-js
const schemeTypes = [
'contrast',
'triade',
'triade',
'tetrade',
'tetrade',
'analogic',
'analogic',
'analogic',
'analogic',
];
const hue = Math.floor( const hue = Math.floor(
parseInt(blockHash.slice(-3), 16) / 4096 * 360 parseInt(blockHash.slice(-3), 16) / 4096 * 360
); );
const schemeFraction = parseInt(blockHash.slice(-5, -3), 16) / 256;
const scheme = schemeTypes[Math.floor(schemeFraction * schemeTypes.length)];
var blockColorScheme = new ColorScheme(); var blockColorScheme = new ColorScheme();
blockColorScheme.from_hue(hue).scheme(scheme).add_complement(true); blockColorScheme.from_hue(hue).scheme('analogic').add_complement(true);
const colors = blockColorScheme.colors(); const colors = blockColorScheme.colors();
console.log('New color scheme: ' + scheme + ' based on %chue ' + hue, 'background-color:#'+colors[0]);
return colors; return colors;
} }
applyColors(target) {
for (var i in this.blockColors) {
const color = this.blockColors[i];
target.style.setProperty(`--color-${i}`, '#'+color);
}
}
onBlock(data) { onBlock(data) {
var completedBlock = document.createElement('div');
completedBlock.className = 'block';
completedBlock.id = data;
this.applyColors(completedBlock);
this.blockColors = App.generateColors(data); this.blockColors = App.generateColors(data);
this.applyColors(this.hero);
var blockLink = document.createElement('a'); var blockLink = document.createElement('a');
blockLink.className = 'explorer-link'; blockLink.className = 'explorer-link';
blockLink.href = document.location + '?block=' + data; blockLink.href = document.location + '?block=' + data;
blockLink.target = '_blank'; blockLink.target = '_blank';
blockLink.setAttribute('rel', 'noopener'); blockLink.setAttribute('rel', 'noopener');
blockLink.appendChild(document.createTextNode('🗗')); blockLink.appendChild(document.createTextNode('🗗'));
this.currentBlock.appendChild(blockLink);
this.currentBlock = document.createElement('div'); fetch('https://insight.dash.org/insight-api/block/' + data)
this.currentBlock.className = 'block'; .then(resp => resp.json())
.then(data => {
if (this.domRefList.unshift(this.currentBlock) > 16) { let mined = [];
var toDelete = this.domRefList.pop(); for (var i in data.tx) {
toDelete.remove(); const txid = data.tx[i];
} let paint = document.getElementById(txid);
this.blockList.insertBefore(this.currentBlock, this.blockList.firstChild); if (paint) {
mined.push(paint);
completedBlock.insertBefore(paint, completedBlock.firstChild);
}
}
this.mempoolRefs = this.mempoolRefs.filter(item => !mined.includes(item));
this.mempoolRefs.forEach(item => {
item.classList.add('stale');
item.data_ignored = item.data_ignored ? item.data_ignored + 1 : 1;
});
this.mempoolRefs.filter(item => {
if (item.data_ignored > 4) {
try {
this.hero.removeChild(item);
} catch (err) { }
return false;
}
return true;
});
completedBlock.appendChild(blockLink);
if (this.blockRefs.unshift(this.completedBlock) > 8) {
let toDelete = this.blockRefs.pop();
if (toDelete) {
toDelete.remove();
}
}
this.blockList.insertBefore(completedBlock, this.blockList.firstChild);
});
} }
static isPrivateSend(components) { static isPrivateSend(components) {
@ -132,36 +153,45 @@ export default class App {
}); });
} }
onTransaction(data) { onTransactionBuilder(target, addToMempool = false) {
const isMixing = App.isPrivateSend(data.vout); return (data) => {
const isInstant = data.txlock || (data.vin && data.vin.length <= 4); const isMixing = App.isPrivateSend(data.vout);
const tx = { const isInstant = data.txlock || (data.vin && data.vin.length <= 4);
mixing: isMixing, const isSimple = data.txlock || (data.vin && data.vin.length <= 1);
instant: isInstant, const tx = {
value: data.valueOut, id: data.txid,
x: parseInt(data.txid.slice(0, 4), 16) / 65536, mixing: isMixing,
y: parseInt(data.txid.slice(4, 8), 16) / 65536, instant: isInstant,
rotation: parseInt(data.txid.slice(16, 17), 16) / 16, simple: isSimple,
paintIndex: parseInt(data.txid.slice(17, 21), 16) / 65536, value: data.valueOut,
color: isMixing ? COLORS.private : isInstant ? COLORS.instant : this.blockColors[ x: parseInt(data.txid.slice(0, 4), 16) / 65536,
Math.floor(parseInt(data.txid.slice(21, 23), 16) / 256 * this.blockColors.length) y: parseInt(data.txid.slice(4, 8), 16) / 65536,
] rotation: parseInt(data.txid.slice(16, 17), 16) / 16,
}; paintIndex: parseInt(data.txid.slice(17, 21), 16) / 65536,
color: isMixing ? COLORS.black : !isSimple ? COLORS.white :
'var(--color-'+
Math.floor(parseInt(data.txid.slice(21, 23), 16) / 256 * this.blockColors.length)+
')'
};
console.log('tx: '+tx.value+(tx.mixing?' mixing':'')+(tx.instant?' instant':'')); var paint = document.createElement('div');
paint.id = tx.id;
var paint = document.createElement('div'); paint.classList.add('paint');
paint.classList.add('paint'); paint.style.maskImage = 'url(assets/paint/' + (tx.value > 10 ?
paint.style.maskImage = 'url(assets/paint/' + (tx.value > 10 ? PAINT.big[Math.floor(tx.paintIndex * 12)] :
PAINT.big[Math.floor(tx.paintIndex * 12)] : PAINT.small[Math.floor(tx.paintIndex * 11)]
PAINT.small[Math.floor(tx.paintIndex * 11)] ) + ')';
) + ')'; paint.style.setProperty('-webkit-mask-image', paint.style.maskImage);
paint.style.setProperty('-webkit-mask-image', paint.style.maskImage); paint.style.setProperty('--x', tx.x);
paint.style.setProperty('--x', tx.x); paint.style.setProperty('--y', tx.y);
paint.style.setProperty('--y', tx.y); paint.style.setProperty('--size', Math.log(1 + tx.value)/Math.log(2));
paint.style.setProperty('--size', Math.log(1 + tx.value)/Math.log(2)); paint.style.setProperty('--rotation', tx.rotation * 360 + 'deg');
paint.style.setProperty('--rotation', tx.rotation * 360 + 'deg'); paint.style.setProperty('--color', tx.color);
paint.style.setProperty('--color', '#'+tx.color); if (addToMempool && this.mempoolRefs.unshift(paint) > 200) {
this.currentBlock.appendChild(paint, this.currentBlock.firstChild); let toDelete = this.mempoolRefs.pop();
toDelete.remove();
}
target.appendChild(paint);
}
} }
}; };

View file

@ -8,6 +8,7 @@
<body> <body>
<div id="connectionStatus" class="is-connecting"></div> <div id="connectionStatus" class="is-connecting"></div>
<div id="hero"></div>
<div id="blockList"></div> <div id="blockList"></div>
<script src="bundle.js"></script> <script src="bundle.js"></script>

View file

@ -7,8 +7,8 @@ export const PSDENOMINATIONS = [
]; ];
export const COLORS = { export const COLORS = {
private: '000000', black: '#000000',
instant: 'ffffff' white: '#ffffff'
}; };
export const PAINT = { export const PAINT = {

View file

@ -34,7 +34,17 @@ a {
margin-left: 80vw; margin-left: 80vw;
padding-top: 2.5vw; padding-top: 2.5vw;
} }
.block:first-child { #hero, .block {
width: 15vw;
height: 15vw;
-webkit-box-shadow: 0.1em 0.1em 1em hsla(0, 0%, 0%, 0.5);
box-shadow: 0.1em 0.1em 1em hsla(0, 0%, 0%, 0.5);
background-color: #dad7b7;
margin: 0 auto 1em;
position: relative;
overflow: hidden;
}
#hero {
position: absolute; position: absolute;
left: 41.125%; left: 41.125%;
top: 50%; top: 50%;
@ -45,26 +55,16 @@ a {
transform: translate(-50%,-50%); transform: translate(-50%,-50%);
} }
@media (max-height: 82.5vw) { @media (max-height: 82.5vw) {
.block:first-child { #hero {
width: calc(100vh - 5vw); width: calc(100vh - 5vw);
height: calc(100vh - 5vw); height: calc(100vh - 5vw);
} }
} }
.block.solo { #hero.solo {
left: 50%; left: 50%;
width: 95vmin; width: 95vmin;
height: 95vmin; height: 95vmin;
} }
.block {
width: 15vw;
height: 15vw;
-webkit-box-shadow: 0.1em 0.1em 1em hsla(0, 0%, 0%, 0.5);
box-shadow: 0.1em 0.1em 1em hsla(0, 0%, 0%, 0.5);
background-color: #dad7b7;
margin: 0 auto 1em;
position: relative;
overflow: hidden;
}
.explorer-link { .explorer-link {
display: none; display: none;
position: absolute; position: absolute;