Viewing Steem Blockchain Data in a Web Browser, Part 11: Javascript "switch" statement and computing owned, delegated, and received Steem Power
This is Part 11 of a series of posts describing how to use the Steem Javascript API to view data from the Steem blockchain in a web browser. The previous 10 posts were:
- Part 1: Text editors and minimal HTML
- Part 2: Metadata, Unicode, and inline CSS
- Part 3: Metadata, nav and footer bars, divs, and HTML entities
- Part 4: Forms, scripts, and the developer console
- Part 5: Using HTML id attributes to modify HTML elements using Javascript
- Part 6: Using the Steem API CDN and the getAccounts() function, and examining the account data model
- Part 7: HTML tables, javascript for/in loop, CSS in the HTML style element
- Part 8: HTML, CSS, and Javascript comments; Javascript functions and MVC
- Part 9: Compute Voting Power and Reputation Score, Javascript "const" and "let" with block scope and loop scope
- Part 10: Calculating the Steem Power and Javascript asynchronous vs. synchronous execution
In the previous post I showed how to compute a user’s steem power. In this post, I write a function that computes all kinds of steem power – owned, delegated, received, and effective.
Steem Power
Steem Power (SP) can be owned, delegated, or received. The "owned" SP (SPo) can be calculated from the “vesting_shares” property of the user account data retrieved using the Steem Javascript API getAccounts() function. The amount of SP "delegated" (SPd) can be calculated from the “delegated_vesting_shares” property of the user account data. The amount of SP "received" (SPr) through delegation by another user can be calculated from the “received_vesting_shares” property of the user account data.
The "effective" SP (SPe) for voting is equal to the amount owned minus the amount delegated plus the amount received.
SPe = SPo - SPd + SPr
Javascript switch statement in a function to compute SP
We will write a javascript function to calculate different types of SP using javascript’s "switch" statement. Switch takes an input parameter and compares it against a list of "cases" and executes a block of code depending on which case is matched by the parameter. It is similar to using an if/elseif chain but is suited to slightly different situations. The function looks like this:
function computeSteemPower(userAccountData, steemPerVests, powerType){
switch(powerType){
case 'vested':
return amount(userAccountData['vesting_shares'])*steemPerVests;
break;
case 'delegated':
return amount(userAccountData['delegated_vesting_shares'])*steemPerVests;
break;
case 'received':
return amount(userAccountData['received_vesting_shares'])*steemPerVests;
break;
case 'effective':
return (amount(userAccountData['vesting_shares'])+
amount(userAccountData['received_vesting_shares'])-
amount(userAccountData['delegated_vesting_shares']))*steemPerVests;
break;
default:
return 9999;
}
}
The userAccountData retrieved using the Steem API getAccounts() function, the steemPerVests computed from the Steem API getDynamicGlobalProperties() function, and the type of SP (powerType) to compute are passed to the computeSteemPower() function and it returns the specified type of SP. The character string in the powerType parameter is compared against the value of each case and if it matches that value, the return statement in the case is executed for the function and the switch statement is broken. If it matches none, then the function returns a default value.
Modifying the HTML table
The HTML table is generated in the callback to a call of the Steem Javascript API getAccounts() function. We now add the different types of SP to this callback in the showUserData() function of the HTML file like so:
function showUserData() {
getElementReferences(['nameForm','dataView']);
getUserInput(htmlElements.nameForm.elements);
steem.api.getDynamicGlobalProperties(function(err,result){
computeSPV(result);
steem.api.getAccounts([userInputs.sUser], function(err,result){
var userData = result[0];
console.log(result);
var dataToTable = {
User_Name: userData.name,
STEEM_Balance: userData.balance,
SBD_Balance: userData.sbd_balance,
Voting_Power: 0,
Reputation_Score: 0,
Reputation_Score_Formatter: 0,
STEEM_POWER: 0
};
dataToTable.Voting_Power = computeVotingPower(userData);
dataToTable.Reputation_Score_Formatter = steem.formatter.reputation(userData.reputation);
dataToTable.Reputation_Score = computeReputationScore(userData);
dataToTable.STEEM_POWER = computeSteemPower(userData,computedValues.steemPerVests,"vested");
dataToTable.STEEM_POWER_Received = computeSteemPower(userData,computedValues.steemPerVests,"received");
dataToTable.STEEM_POWER_Delegated = computeSteemPower(userData,computedValues.steemPerVests,"delegated");
dataToTable.STEEM_POWER_Effective = computeSteemPower(userData,computedValues.steemPerVests,"effective");
var theText = generateTable('Metric', 'Value',dataToTable);
htmlElements.dataView.innerHTML = theText;
});
});
}
Notice that the STEEM_POWER_Received, STEEM_POWER_delegated, and STEEM_POWER_effective keys are not specified when the dataToTable{} Object is declared. This is an example of the rule that properties can be added to Javascript Objects after they are declared.
Inserting the functions from part 10 of this series, and the computeSteemPower() function written here, and the new showUserData() function into the HTML document from part 9 gives an HTML document that looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Show a Steemit User's Account Data">
<title>Show User's Data</title>
<script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>
<style>
td,th,footer,nav {
border: 1px solid black;
}
table {
width: 100%;
}
div {
padding: 10px;
margin: 5px;
background-color: pink;
}
#dataView {
background-color: lightsalmon;
overflow: auto;
height: 300px;
}
#formDiv {
background-color: lightblue;
}
</style>
</head>
<body>
<nav>
</nav>
<br>
<div id="formDiv">
<br>
<form action="#" onsubmit="showUserData();return false;" id="nameForm">
Enter your steemit userName: <input type="text" name="sUser" id="userNid">
<input type="submit" value="Submit">
</form>
<br>
</div>
<div id="dataView">
<br>
<p></p>
<br>
</div>
<br>
<footer>
</footer>
<script>
var htmlElements = {};
var userInputs = {};
function generateTable(header1,header2,objectToTable){
var tableText = "<table>";
tableText = tableText+"<tr><th>"+header1+"</th><th>"+header2+"</th></tr>";
for (var key in objectToTable){
var keyStr = key.replace(/_/g," ");
tableText = tableText+"<tr><td>"+keyStr+"</td><td>"+objectToTable[key]+"</td></tr>";
}
tableText = tableText+"</table>";
return tableText;
}
function computeVotingPower(userAccountData){
var lastVoteTime = userAccountData.last_vote_time;
var votingPower = userAccountData.voting_power;
var timeBeforeNow = (Date.now() - new Date(lastVoteTime+"Z"))/1000;
var votingPowerNow = Math.min(votingPower/100+timeBeforeNow*20/86400,100).toFixed(2);
return votingPowerNow+"%";
}
function computeReputationScore(userAccountData){
var repScore = Math.sign(userAccountData.reputation)*userAccountData.reputation;
repScore = Math.log10(repScore);
if(isNaN(repScore)){repScore = 0};
repScore = Math.max(repScore-9,0);
repScore = Math.sign(repScore)*repScore;
repScore = (repScore*9)+25;
repScore = repScore.toFixed(2);
return repScore;
}
function getElementReferences(elementNames){
for (index in elementNames){
var name = elementNames[index];
htmlElements[name] = document.getElementById(name);
}
}
function getUserInput(formElements){
for( var i=0;i<formElements.length;i++){
if(formElements[i].name !== ""){
userInputs[formElements[i].name]=formElements[i].value;
}
}
}
var computedValues = {steemPerVests: 0.005};
function amount(labeledValue){
return parseFloat(labeledValue.split(" ")[0]);
}
function computeSPV(dgp){
var tvfs = amount(dgp['total_vesting_fund_steem']);
var tvs = amount(dgp['total_vesting_shares']);
computedValues.steemPerVests = tvfs/tvs;
}
function computeSteemPower(userAccountData,steemPerVests,powerType){
switch(powerType){
case 'vested':
return amount(userAccountData['vesting_shares'])*steemPerVests;
break;
case 'delegated':
return amount(userAccountData['delegated_vesting_shares'])*steemPerVests;
break;
case 'received':
return amount(userAccountData['received_vesting_shares'])*steemPerVests;
break;
case 'effective':
return (amount(userAccountData['vesting_shares'])+
amount(userAccountData['received_vesting_shares'])-
amount(userAccountData['delegated_vesting_shares']))*steemPerVests;
break;
default:
return 9999;
}
}
function showUserData() {
getElementReferences(['nameForm','dataView']);
getUserInput(htmlElements.nameForm.elements);
steem.api.getDynamicGlobalProperties(function(err,result){
computeSPV(result);
steem.api.getAccounts([userInputs.sUser], function(err,result){
var userData = result[0];
console.log(result);
var dataToTable = {
User_Name: userData.name,
STEEM_Balance: userData.balance,
SBD_Balance: userData.sbd_balance,
Voting_Power: 0,
Reputation_Score: 0,
Reputation_Score_Formatter: 0,
STEEM_POWER: 0
};
dataToTable.Voting_Power = computeVotingPower(userData);
dataToTable.Reputation_Score_Formatter = steem.formatter.reputation(userData.reputation);
dataToTable.Reputation_Score = computeReputationScore(userData);
dataToTable.STEEM_POWER = computeSteemPower(userData,computedValues.steemPerVests,"vested");
dataToTable.STEEM_POWER_Received = computeSteemPower(userData,computedValues.steemPerVests,"received");
dataToTable.STEEM_POWER_Delegated = computeSteemPower(userData,computedValues.steemPerVests,"delegated");
dataToTable.STEEM_POWER_Effective = computeSteemPower(userData,computedValues.steemPerVests,"effective");
var theText = generateTable('Metric', 'Value',dataToTable);
htmlElements.dataView.innerHTML = theText;
});
});
}
</script>
</body>
</html>
Placing this text in a file using a text editor, loading the file into a web browser, entering a valid steemit username in the text field, and pressing the submit button makes the web browser look something like this: