We can save data to our browser's localStorage object, which persists through browser and system restarts, and has no built-in expiration date. This type of storage is good for small data objects such as user preferences, settings, or high scores.
Note 2:
localStorageis not shared between different browsers or systems. Additionally, incognito browser tabs will use a differentlocalStoragewhich automatically clears when the tab or window is closed.
We can use graphico's built-in functions to save data, load data, or clear data from localStorage. We can assign a "namespace" to differentiate our data from basic browser local storage and from different data sets that we define. For example, we can have multiple user profiles, where each user profile lives in its own namespace. For safety, we can only clear namespaces that we define when saving data.
Note 1:
localStoragecan be completely cleared by clearing your browser's data.
In this example we do just that - we define a set of user profiles, each containing data of the amount of time each key was pressed. (The canvas must be focused in order to capture keyboard input.) We can switch between different user profiles to see that a unique dataset was saved under each profile.
Security Enhancements
If you use the Inspect Element tool (on any website or web app), you can see your local storage by typing
localStoragein the console, and you'll notice that most of these are stored in readable text. For slightly better security,graphicoautomatically encodes and decodes this data with a base64 encoding so it cannot be directly read and edited as easily using Inspect Element.
Follow these steps to create a new webpack project and install the graphico dependency to run this example.
# Create and open project folder
mkdir Save_Data_demo
cd Save_Data_demo
# Initialize project and install dependencies
npm init -y
npm pkg set type="module"
npm i graphico@1.3.0 webpack-cli
# Create source files
touch index.html
mkdir src
touch src/index.js
# Open new files
open index.html
open src/index.js
Copy and paste the following source code blocks into the newly created files.
<html>
<head>
<script type="text/javascript" src="dist/main.js" defer></script>
</head>
<body></body>
</html>
import { Canvas } from 'graphico';
class Text {
#text;
#x;
#y;
#size;
#color;
#align;
#baseline;
constructor(x = 0, y = 0, size = 12, color = 'black', align = 'center', baseline = 'middle') {
this.#x = x;
this.#y = y;
this.#size = size;
this.#color = color;
this.#align = align;
this.#baseline = baseline;
}
setText(text = '') {
this.#text = text;
}
draw(graphics) {
graphics.fillStyle = this.#color;
graphics.font = `bold ${this.#size}px monospace`;
graphics.textAlign = this.#align;
graphics.textBaseline = this.#baseline;
this.#text.split('\n').forEach((line, num) => {
graphics.fillText(line, this.#x, this.#y + num * this.#size * 1.5);
});
}
}
// Define the signed-in user and their data
let user = 'none';
let data = {};
// Create text elements
const profile = new Text(10, 10, 24, 'black', 'left', 'top');
const action = new Text(10, 50, 20, 'gray', 'left', 'top');
const instruct = new Text(10, 100, 20, 'orange', 'left', 'top');
const raw = new Text(300, 350);
// Set static text for action and instructions
action.setText('No action taken');
instruct.setText(`Instructions:
1-9 = Load user profile.
0 = Log out.
s = Save data.
x = Clear data for current profile.
<any key> = Count # of times pressed.`);
const canv = new Canvas({
border: 'black',
borderBlur: 'lightgray',
width: 600,
height: 400,
keydown(key) {
if (/[1-9]/.test(key)) {
// Pull up a user's profile
user = `user${key}`;
data = canv.loadData(user) ?? {}; // loadData may be undefined, so default to empty object
action.setText(`Loaded data for ${user}!`);
} else if (key === '0') {
// Log out of the current user
user = 'none';
data = {};
action.setText('Logged out.');
} else if (key === 's' && user !== 'none') {
// Save user data
canv.saveData(data, user);
action.setText(`Saved data for ${user}!`);
} else if (key === 'x') {
// Clear user data
data = {};
canv.clearData(user);
action.setText('Cleared all data.');
} else if (user !== 'none') {
// Count up the number of times pressed
if (typeof data[key] === 'number') {
data[key]++;
} else {
data[key] = 1;
}
action.setText(`Pressed key: ${key}. Total = ${data[key]}`);
}
},
loop(dt) {
profile.setText(`Current profile: ${user}.`);
raw.setText(JSON.stringify(data));
canv.clear();
canv.draw(profile);
canv.draw(action);
canv.draw(instruct);
canv.draw(raw);
},
});
In the base project directory Save_Data_demo/, run the following command. If changes are made in the source files, the demo will automatically be recompiled. Press CTRL+C to stop running.
npx webpack --mode development --watch
Open the index.html file in any web browser of your choice! You should see a page similar to the one below.