Real-Time Block Visualizer with Vue
This tutorial shows how to include the algosdk library to read Algorand data within a Vue project.
We’ll display falling squares in a canvas where each unit represents an Algorand blockchain block creation in real-time. Completing this tutorial will set you up for developing more complex Algorand applications with Vue.
Requirements
Required:
Optional:
Background
Vue.js is a Javascript progressive framework for building user interfaces meanwhile p5.js is a library for creative coding with a focus on making coding accessible and inclusive. Combining their capabilities with Algorand’s data we are able to quickly create interesting and delightful projects.
Steps
1. Set Up Your Environment
You can use the PureStake API Service as a way to connect to the network or you can spin up a dockerized Algorand node using the sandbox. Once you have that you can now get a new Vue app up and running by using the following command:
vue create algo-vue
Make sure you have node and Vue installed on your machine. This sets up and configures your dev environment for you. When prompted about it choose the default preset.
Go inside our newly created Vue project and make sure to install the algosdk and the vue-p5 libraries.
cd algo-vue
npm install algosdk vue-p5
To learn more visit Introducing Sandbox
2. Create the Basic Vue App
Start by opening the base component file src/App.vue
.
For this tutorial, we’ll create an extra component named AlgoViz in where we’ll handle both Algorand’s fetching of data and it’s visualization with P5.
Edit the default app template to include this new component.
<template>
<div id="app">
<AlgoViz />
</div>
</template>
<script>
import AlgoViz from './components/AlgoViz.vue'
export default {
name: 'App',
components: {
AlgoViz
}
}
</script>
To learn more about vue components visit the Components Basics Doc
3. Create Algorand-P5 Component
Create the new component src/components/AlgoViz.vue
. Include VueP5 component for displaying a canvas to interact with and also make sure to include Algorand component (not yet created) where we’ll handle all connections to the Algorand blockchain.
<template>
<div class="container">
<h1>Last block id: {{ lastRound }}</h1>
<Algorand @lastRound="updateStatus" />
<VueP5 @setup="setup" @draw="draw"></VueP5>
</div>
</template>
<script>
import VueP5 from "vue-p5";
import Algorand from "./Algorand";
export default {
name: "AlgoViz",
components: {
VueP5,
Algorand
},
data: () => ({
lastRound: undefined
}),
methods: {
setup(sketch) {
// ...
},
draw(sketch) {
// ...
},
updateStatus(lastRound) {
this.lastRound = lastRound
}
}
}
</script>
Template
VueP5
This component emits 2 types of events, draw and setup. The setup()
event runs once and is typically used for initialization or for creating a program that does not need a loop running code repeatedly. The draw()
event runs repeatedly, and is used for animation.
To learn more about P5 functions visit the P5 Overview Doc
Algorand
With this component we’ll emit the lastRound
event to return the last block id for every new block written to the Algorand blockchain.
To learn more about vue events visit the Event Handling Doc
Script
Start by doing the basic structure and fill the details as we progress.
Import both VueP5 and Algorand components. Create the 3 necessary methods we’ll be using after catching their corresponding events. The only data variable is lastRound
for keeping track of the ID of the latest block.
4. Connect to the Algorand Blockchain
It’s time to create src/components/Algorand.vue
.
It won’t have any html code, only a placeholder.
You need to import the algosdk library. Make sure to use your pureStakeKey (or the sandbox credentials) and select any of the Algorand’s Networks (Beta, Testnet, Mainnet). This connection will be kept alive as long as the website is open.
On component creation get the latest block and emit a message with its ID. Wait for a newly created block, emit a new message and repeat.
<template>
<div></div>
</template>
<script>
// CONSTANTS
const pureStakeKey = "YOUR_API_KEY";
const algosdk = require("algosdk");
const baseServer = "https://testnet-algorand.api.purestake.io/ps2";
const port = "";
const token = {
"X-API-Key": pureStakeKey
};
const algodClient = new algosdk.Algodv2(token, baseServer, port);
export default {
created () {
this.waitForNewBlock();
},
methods: {
async waitForNewBlock() {
let status = (await algodClient.status().do());
let lastRound = status["last-round"];
// eslint-disable-next-line no-constant-condition
while (true) {
this.$emit('lastRound', lastRound)
lastRound++;
await algodClient.statusAfterBlock(lastRound).do();
}
}
}
}
</script>
Run npm run serve
so you can visit http://localhost:8080/ and see everything in action. It will only show the title displaying the ID of the latest block and a blank canvas below.
To learn more about the created function refer to the Lifecycle Diagram
5. Display Falling Blocks
Go back to the Algoviz component as we’ll start filling the gaps
data
The data for this component includes the desired width
and height
defined in pixels for the canvas. Specify the size
in pixels for the falling squares. And the last requirement is an empty array blocks
to keep track of the squares and their properties.
<script>
export default {
// ...
data: () => ({
w: 600,
h: 600,
size: 20,
blocks: [],
lastRound: undefined
})
// ...
}
setup
A canvas with the dimensions defined in data is created. We’ll use a frameRate of 1 and a white background.
<script>
export default {
// ...
methods: {
setup(sketch) {
sketch.createCanvas(this.w, this.h);
sketch.frameRate(1);
sketch.background(255);
sketch.noStroke();
},
// ...
}
// ...
}
draw
Each time the draw function is called the canvas will be painted with a white layer at 50% opacity creating a tail effect for our squares.
We want to update the vertical position of each block so they move one step closer to the bottom every frame, a step being the size of the square.
Update the fill tool before drawing the square so that it uses the block’s predefined color.
<script>
export default {
// ...
methods: {
// ...
draw(sketch) {
sketch.background(255,255,255,128);
this.blocks.forEach(block => {
block.y += 1;
sketch.fill(block.color.r, block.color.g, block.color.b);
sketch.rect(
block.x * this.size,
block.y * this.size,
this.size,
this.size
);
});
},
// ...
}
// ...
}
updateStatus
If a new block is found, a random color and a random x
position at the top is assigned to it before joining the block list.
<script>
export default {
// ...
methods: {
// ...
getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
},
updateStatus(lastRound) {
this.lastRound = lastRound
const newBlock = {
id: lastRound,
y: 0,
x: this.getRandomInt(this.w / this.size),
color: {
r: this.getRandomInt(255),
g: this.getRandomInt(255),
b: this.getRandomInt(255)
}
};
console.log(newBlock);
this.blocks.push(newBlock);
}
}
// ...
}
6. All Together
You can now leverage your web apps with an Algorand-Vue integration for creating more complex and interesting applications.
Here is the complete code for Algoviz.
<template>
<div class="container">
<h1>Last block id: {{ lastRound }}</h1>
<Algorand @lastRound="updateStatus" />
<VueP5 @setup="setup" @draw="draw"></VueP5>
</div>
</template>
<script>
import VueP5 from "vue-p5";
import Algorand from "./Algorand";
export default {
name: "AlgoViz",
components: {
VueP5,
Algorand
},
data: () => ({
w: 600,
h: 600,
size: 20,
blocks: [],
lastRound: undefined
}),
methods: {
setup(sketch) {
sketch.createCanvas(this.w, this.h);
sketch.frameRate(1);
sketch.background(255);
sketch.noStroke();
},
draw(sketch) {
sketch.background(255,255,255,128);
this.blocks.forEach(block => {
block.y += 1;
sketch.fill(block.color.r, block.color.g, block.color.b);
sketch.rect(
block.x * this.size,
block.y * this.size,
this.size,
this.size
);
});
},
getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
},
updateStatus(lastRound) {
this.lastRound = lastRound
const newBlock = {
id: lastRound,
y: 0,
x: this.getRandomInt(this.w / this.size),
color: {
r: this.getRandomInt(255),
g: this.getRandomInt(255),
b: this.getRandomInt(255)
}
};
console.log(newBlock);
this.blocks.push(newBlock);
}
}
};
</script>