Created
September 25, 2021 19:06
-
-
Save frol/307c5058b458ddff48dda483f4463131 to your computer and use it in GitHub Desktop.
Live Transactions visualization on NEAR mainnet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://youtu.be/2WXaosLThBY | |
import React, { useState, useEffect } from "react"; | |
import ReactEcharts from "echarts-for-react"; | |
import echarts from "echarts"; | |
import { Tabs, Tab } from "react-bootstrap"; | |
import StatsApi, { AccountsByDate } from "../../libraries/explorer-wamp/stats"; | |
import { Props } from "./TransactionsByDate"; | |
import { Translate } from "react-localize-redux"; | |
const AccountChangesFlow = ({ chartStyle }: Props) => { | |
const [uniqueAccounts, setUniqueAccounts] = useState(new Map()); | |
const [accountChanges, setAccountChanges] = useState([]); | |
useEffect(async () => { | |
const statsApi = new StatsApi(); | |
const result = await statsApi.call('select:INDEXER_BACKEND', [ | |
`select | |
account_changes.changed_in_block_timestamp as last_changed_in_block_timestamp, | |
account_changes.index_in_block as last_index_in_block | |
from account_changes | |
order by changed_in_block_timestamp desc, index_in_block desc | |
limit 1` | |
] | |
); | |
console.log("eff3", result) | |
let { last_changed_in_block_timestamp, last_index_in_block } = result[0]; | |
console.log(last_changed_in_block_timestamp, last_index_in_block) | |
const pullAccountChanges = async () => { | |
const newAccountChanges = await statsApi.call('select:INDEXER_BACKEND', [ | |
`select | |
account_changes.changed_in_block_timestamp, | |
account_changes.index_in_block, | |
receipts.predecessor_account_id, | |
receipts.receiver_account_id | |
from account_changes | |
join receipts on account_changes.caused_by_receipt_id = receipts.receipt_id | |
where | |
receipts.predecessor_account_id != 'system' and | |
receipts.predecessor_account_id != receipts.receiver_account_id and | |
( | |
changed_in_block_timestamp > :last_changed_in_block_timestamp or | |
(changed_in_block_timestamp = :last_changed_in_block_timestamp and index_in_block > :last_index_in_block) | |
) | |
order by changed_in_block_timestamp desc, index_in_block desc`, | |
{ | |
last_changed_in_block_timestamp, | |
last_index_in_block, | |
} | |
]); | |
if (newAccountChanges.length > 0) { | |
last_changed_in_block_timestamp = newAccountChanges[0].changed_in_block_timestamp; | |
last_index_in_block = newAccountChanges[0].index_in_block; | |
} | |
/* | |
setUniqueAccounts((state) => { | |
newAccountChanges.forEach(({ predecessor_account_id, receiver_account_id }) => { | |
state.add(predecessor_account_id) | |
state.add(receiver_account_id) | |
}) | |
return state | |
}) | |
*/ | |
setAccountChanges((oldAccountChanges) => { | |
const uniqueAccounts = new Map(); | |
oldAccountChanges.forEach(({ predecessor_account_id, receiver_account_id }) => { | |
uniqueAccounts.set(predecessor_account_id, (uniqueAccounts.get(predecessor_account_id) || 0) + 1) | |
uniqueAccounts.set(receiver_account_id, (uniqueAccounts.get(receiver_account_id) || 0) + 1) | |
}) | |
newAccountChanges.forEach(({ predecessor_account_id, receiver_account_id }) => { | |
uniqueAccounts.set(predecessor_account_id, (uniqueAccounts.get(predecessor_account_id) || 0) + 1) | |
uniqueAccounts.set(receiver_account_id, (uniqueAccounts.get(receiver_account_id) || 0) + 1) | |
}) | |
setUniqueAccounts(uniqueAccounts); | |
const oldAccountChangesCount = Math.max(0, 300 - newAccountChanges.length); | |
return [...oldAccountChanges.slice(-oldAccountChangesCount), ...newAccountChanges] | |
}) | |
}; | |
let timer; | |
const iterate = async () => { | |
await pullAccountChanges(); | |
timer = setTimeout(iterate, 1000); | |
}; | |
timer = setTimeout(iterate, 0); | |
return () => { | |
clearTimeout(timer) | |
} | |
}, []); | |
const getOption = () => { | |
const categories = [ | |
"0", | |
"1", | |
"2", | |
"3", | |
"4", | |
"5", | |
"6", | |
"7", | |
"8", | |
"9", | |
]; | |
console.log(accountChanges) | |
return { | |
title: { | |
text: 'Live NEAR Transactions', | |
subtext: 'Circular layout', | |
top: 'bottom', | |
left: 'right' | |
}, | |
tooltip: {}, | |
/*legend: [ | |
{ | |
data: graph.categories.map(function (a) { | |
return a.name; | |
}) | |
} | |
],*/ | |
animationDurationUpdate: 1000, | |
animationEasingUpdate: 'quinticInOut', | |
series: [ | |
{ | |
name: 'NEAR Transactions', | |
type: 'graph', | |
layout: 'circular', | |
circular: { | |
rotateLabel: true | |
}, | |
data: [...uniqueAccounts.entries()].map(([accountId, edges]) => ({ category: edges > 10 ? 9 : edges, name: accountId, symbolSize: edges, label: { show: true } })), | |
links: accountChanges.map(({ predecessor_account_id: source, receiver_account_id: target }) => ({ source, target })), | |
categories: categories, | |
roam: true, | |
label: { | |
position: 'right', | |
formatter: '{b}' | |
}, | |
lineStyle: { | |
color: 'source', | |
curveness: 0.3 | |
} | |
} | |
] | |
}; | |
}; | |
return ( | |
<ReactEcharts | |
option={getOption()} | |
style={{ height: 1000 }} | |
/> | |
); | |
}; | |
export default AccountChangesFlow; |
@ilyar yeah, I used gource as a source of inspiration. Unfortunately, there is nothing I can reuse from gource
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👍 JFYI https://gource.io/