Love is All. Love U Planet.

This commit is contained in:
fred 2023-09-01 19:41:43 +02:00
parent 2625f571d2
commit cd6e36e57d
12 changed files with 839 additions and 5 deletions

82
G1PUB2IPNS.html Normal file
View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<title>G1 to IPNS Public Key Conversion</title>
</head>
<body>
<h1>G1 to IPNS Public Key Conversion</h1>
<input type="text" id="g1PublicKey" size=40 placeholder="Enter G1 Public Key">
<button onclick="convertPublicKey()">Convert</button>
<p>IPNS Public Key:</p>
<p id="ipnsPublicKey"></p>
<!-- Include the tweetnacl library for Ed25519 operations -->
<script src="./nacl.min.js"></script>
<script>
// Custom Base58 encoding and decoding functions
function base58Encode(bytes) {
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const base = BigInt(ALPHABET.length);
let encoded = '';
let value = BigInt('0');
for (let i = 0; i < bytes.length; i++) {
value = value * BigInt(256) + BigInt(bytes[i]);
}
while (value > BigInt(0)) {
const remainder = value % base;
value = value / base;
encoded = ALPHABET[Number(remainder)] + encoded;
}
return encoded;
}
function base58Decode(encoded) {
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const base = BigInt(ALPHABET.length);
let value = BigInt('0');
for (let i = 0; i < encoded.length; i++) {
const char = encoded[i];
const charValue = BigInt(ALPHABET.indexOf(char));
value = value * base + charValue;
}
const valueBytes = [];
while (value > BigInt(0)) {
const byteValue = Number(value % BigInt(256));
value = value / BigInt(256);
valueBytes.unshift(byteValue);
}
return new Uint8Array(valueBytes);
}
function convertPublicKey() {
const g1PublicKey = document.getElementById("g1PublicKey").value;
// Decode the Base58 encoded G1 public key using custom function
const decodedShared = base58Decode(g1PublicKey);
// Create a new Uint8Array to hold the IPNS public key bytes
const ipnsPublicKeyBytes = new Uint8Array(decodedShared.length + 6);
// Prefix bytes for IPNS public key
const prefixBytes = new Uint8Array([0, 36, 8, 1, 18, 32]);
// Copy the prefix bytes and G1 public key bytes into the new array
ipnsPublicKeyBytes.set(prefixBytes, 0);
ipnsPublicKeyBytes.set(decodedShared, prefixBytes.length);
// Encode the IPNS public key using custom Base58 encoding
const ipnsPublicKey = '1' + base58Encode(ipnsPublicKeyBytes); // Prepend '1'
document.getElementById("ipnsPublicKey").innerText = ipnsPublicKey;
}
</script>
</body>
</html>

View File

@ -17,5 +17,8 @@ You receive an access to this crypto landing recorded into IPFS
Get Friends.
Explore Trust.
https://ipfs.copylaradio.com/ipfs/QmbVVpUUBEkp35oMKUmdYyw4SWEQsFeJnxW5EPa5tAyfQn/
For LOCALHOST : http://ipfs.localhost:8080/ipfs/Qme4r4fHf6VfaqoXobTnzjWVwBRhRPzMazJyrZ9ubbdJMP/ (PROD)
For WAN : https://ipfs.copylaradio.com/ipfs/QmZjtNz7iNgPiULbyT2Zyi6QHGXt8WqKo1DzKkM5EKPLfL/ (DEMO ONLY)
Enjoy the visit.

View File

@ -77,7 +77,9 @@
// Provide the latitude for adjustment
const latitude = centerLat;
const zoomLevel = calculateZoomLevel(desiredImageWidthInKm, latitude);
const zoomLevel = calculateZoomLevel(desiredImageWidthInKm, latitude);
// const zoomLevel = calculateZoomLevel(desiredImageWidthInKm, latitude) + 2;
console.log('Recommended zoom level:', zoomLevel);
const map = L.map('map', {
@ -98,6 +100,7 @@
//~ maxZoom: 18
//~ }).addTo(map);
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: `U Planet | Astroport | ${southWestLat} : ${southWestLon}`
}).addTo(map);

150
earth/g12ipns.html Normal file
View File

@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<title>G1 to IPNS Public Key Conversion</title>
</head>
<body>
<h1>G1 to IPNS Public Key Conversion</h1>
<input type="text" id="g1PublicKey" size=40 placeholder="Enter G1 Public Key">
<button onclick="convertPublicKey()">Convert</button>
<p>IPNS Public Key:</p>
<p id="ipnsPublicKey"></p>
<br>
<h1>Generate Seed from Salt and Password</h1>
<p>Generate Seed:</p>
<form id="generateSeedForm">
<label for="salt">Salt:</label>
<input type="text" id="salt" name="salt" required>
<br>
<label for="password">Password:</label>
<input type="text" id="password" name="password" required>
<br>
<button type="submit">Generate Seed</button>
</form>
<p>Generated Seed:</p>
<p id="generatedSeed"></p>
<!-- Include the tweetnacl library for Ed25519 operations -->
<script src="./nacl.min.js"></script>
<!-- Include the scrypt-async library for scrypt key derivation -->
<script src="./scrypt-async.min.js"></script>
<script>
function generateSeed(salt, password, scryptParams) {
return new Promise((resolve, reject) => {
scrypt(
password,
salt,
scryptParams.N,
scryptParams.r,
scryptParams.p,
scryptParams.seedLength,
function (seedArrayBuffer) {
// Convert the ArrayBuffer to a Uint8Array
const seedBytes = new Uint8Array(seedArrayBuffer);
resolve(seedBytes);
},
function (error) {
reject(error);
}
);
});
}
document.getElementById("generateSeedForm").addEventListener("submit", async function (event) {
event.preventDefault();
const salt = document.getElementById("salt").value;
const password = document.getElementById("password").value;
// Define the scrypt parameters
const scryptParams = {
N: 16384, // N parameter
r: 8, // r parameter
p: 8, // p parameter
seedLength: 64 // Seed length in bytes
};
try {
// Call the generateSeed function with the defined parameters
const seed = await generateSeed(salt, password, scryptParams);
// Now you can use the generated seed as needed
document.getElementById("generatedSeed").innerText = Array.from(seed).map(byte => ('00' + byte.toString(16)).slice(-2)).join('');
} catch (error) {
console.error(error);
alert("Error generating seed: " + error.message); // Display the error message
}
});
</script>
<script>
// Custom Base58 encoding and decoding functions
function base58Encode(bytes) {
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const base = BigInt(ALPHABET.length);
let encoded = '';
let value = BigInt('0');
for (let i = 0; i < bytes.length; i++) {
value = value * BigInt(256) + BigInt(bytes[i]);
}
while (value > BigInt(0)) {
const remainder = value % base;
value = value / base;
encoded = ALPHABET[Number(remainder)] + encoded;
}
return encoded;
}
function base58Decode(encoded) {
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const base = BigInt(ALPHABET.length);
let value = BigInt('0');
for (let i = 0; i < encoded.length; i++) {
const char = encoded[i];
const charValue = BigInt(ALPHABET.indexOf(char));
value = value * base + charValue;
}
const valueBytes = [];
while (value > BigInt(0)) {
const byteValue = Number(value % BigInt(256));
value = value / BigInt(256);
valueBytes.unshift(byteValue);
}
return new Uint8Array(valueBytes);
}
function convertPublicKey() {
const g1PublicKey = document.getElementById("g1PublicKey").value;
// Decode the Base58 encoded G1 public key using custom function
const decodedShared = base58Decode(g1PublicKey);
// Create a new Uint8Array to hold the IPNS public key bytes
const ipnsPublicKeyBytes = new Uint8Array(decodedShared.length + 6);
// Prefix bytes for IPNS public key
const prefixBytes = new Uint8Array([0, 36, 8, 1, 18, 32]);
// Copy the prefix bytes and G1 public key bytes into the new array
ipnsPublicKeyBytes.set(prefixBytes, 0);
ipnsPublicKeyBytes.set(decodedShared, prefixBytes.length);
// Encode the IPNS public key using custom Base58 encoding
const ipnsPublicKey = '1' + base58Encode(ipnsPublicKeyBytes); // Prepend '1'
document.getElementById("ipnsPublicKey").innerText = ipnsPublicKey;
}
</script>
</body>
</html>

52
earth/g1gate.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang=""><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Ğ1Gate 🜶 Là où va la Ğ1</title>
<meta name="description" content="Explorez la blockchain Ğ1 de façon visuelle pour découvrir où partent toutes ces Ğ1.">
<link rel="stylesheet" type="text/css" href="g1gate_fichiers/styles.css" title="G1Gate">
</head>
<body>
<header>
<h1>Où va la Ğ1…</h1>
<p id="description">
Explorez la blockchain Ğ1 pour savoir où va la Ğ1.
</p>
</header>
<form method="get" action="#expenses" id="explore">
<p>
<label>
Clef à explorer&nbsp;:<br>
<input type="text" name="pubkey" size="50" value="EA7Dsw39ShZg4SpURsrgMaMqrweJPUFPYHwZA8e92e3D">
</label>
</p>
<p>
<label>
Limite du nombre de transactions&nbsp;:
<input type="number" name="txLimit" value="30" size="5">
</label>
</p>
<p>
<input type="submit" label="Explorer">
</p>
</form>
<section id="expenses"><h2>Dépenses de <q>sasa vava</q></h2><article class="svg-container"><svg viewBox="0,0,1280,720" width="1280" height="720" style="max-width: 100%; height: auto; height: intrinsic;" font-family="sans-serif" font-size="10"><a xlink:href="#Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm" target="_self" transform="translate(0,0)"><rect fill="#FFC431" fill-opacity="1" width="1242" height="720"></rect><title>4 DU</title><clipPath id="O-378df07a9583b-clip-0"><rect width="1242" height="720"></rect></clipPath><text clip-path="url(https://g1.quest/g1gate/#O-378df07a9583b-clip-0)"><tspan x="3" y="1.4000000000000001em" fill-opacity="0.7">Tortue</tspan></text></a><a xlink:href="#5nHhk6wwHELKPn5zvUYjzK9gN1iT214udKyXg5PFazq3" target="_self" transform="translate(1242,0)"><rect fill="#548AFF" fill-opacity="1" width="38" height="720"></rect><title>1 DU</title><clipPath id="O-378df07a9583b-clip-1"><rect width="38" height="720"></rect></clipPath><text clip-path="url(https://g1.quest/g1gate/#O-378df07a9583b-clip-1)"><tspan x="3" y="1.4000000000000001em" fill-opacity="0.7">No tune</tspan></text></a></svg></article></section>
<footer>
<blockquote>
Follow the money
</blockquote>
</footer>
<script type="module" src="g1gate_fichiers/app.js">
</script>
</body></html>

View File

@ -0,0 +1,488 @@
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
export const DU = 10.68;
export const MAX_NB_TX = 30;
export const CESIUM_G1_NODES = [
"https://g1.data.brussels.ovh",
"https://g1.data.e-is.pro",
"https://g1.data.cuates.net",
"https://g1.data.madeirawonders.com",
// "https://g1.data.pini.fr" // Could not resolve hostname
// "https://g1.data.le-sou.org" // vide
// "https://abyayala.g1labs.net" // /g1/movement returns "404 Not Found"
// "https://g1.data.presles.fr", // CORS
// "https://cesiumplus971.dns1.us", // CORS
// "https://g1.data.mithril.re", // /g1/movement returns "403 Forbidden"
];
let chartColors = [
'#FFC431',
'#548AFF',
'#FF826E',
'#67B0C3',
'#CFD8DC',
'#5CD6B3'
];
export const Treemap = (
// Copyright 2021-2023 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/treemap
function Treemap(data, { // data is either tabular (array of objects) or hierarchy (nested objects)
path, // as an alternative to id and parentId, returns an array identifier, imputing internal nodes
id = Array.isArray(data) ? d => d.id : null, // if tabular data, given a d in data, returns a unique identifier (string)
parentId = Array.isArray(data) ? d => d.parentId : null, // if tabular data, given a node d, returns its parents identifier
children, // if hierarchical data, given a d in data, returns its children
value, // given a node d, returns a quantitative value (for area encoding; null for count)
sort = (a, b) => d3.descending(a.value, b.value), // how to sort nodes prior to layout
label, // given a leaf node d, returns the name to display on the rectangle
group, // given a leaf node d, returns a categorical value (for color encoding)
title, // given a leaf node d, returns its hover text
link, // given a leaf node d, its link (if any)
linkTarget = "_blank", // the target attribute for links (if any)
tile = d3.treemapBinary, // treemap strategy
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
margin = 0, // shorthand for margins
marginTop = margin, // top margin, in pixels
marginRight = margin, // right margin, in pixels
marginBottom = margin, // bottom margin, in pixels
marginLeft = margin, // left margin, in pixels
padding = 1, // shorthand for inner and outer padding
paddingInner = padding, // to separate a node from its adjacent siblings
paddingOuter = padding, // shorthand for top, right, bottom, and left padding
paddingTop = paddingOuter, // to separate a nodes top edge from its children
paddingRight = paddingOuter, // to separate a nodes right edge from its children
paddingBottom = paddingOuter, // to separate a nodes bottom edge from its children
paddingLeft = paddingOuter, // to separate a nodes left edge from its children
round = true, // whether to round to exact pixels
colors = d3.schemeTableau10, // array of colors
zDomain, // array of values for the color scale
fill = "#ccc", // fill for node rects (if no group color encoding)
fillOpacity = group == null ? null : 0.6, // fill opacity for node rects
stroke, // stroke for node rects
strokeWidth, // stroke width for node rects
strokeOpacity, // stroke opacity for node rects
strokeLinejoin, // stroke line join for node rects
} = {}) {
// If id and parentId options are specified, or the path option, use d3.stratify
// to convert tabular data to a hierarchy; otherwise we assume that the data is
// specified as an object {children} with nested objects (a.k.a. the “flare.json”
// format), and use d3.hierarchy.
// We take special care of any node that has both a value and children, see
// https://observablehq.com/@d3/treemap-parent-with-value.
const stratify = data => (d3.stratify().path(path)(data)).each(node => {
if (node.children?.length && node.data != null) {
const child = new d3.Node(node.data);
node.data = null;
child.depth = node.depth + 1;
child.height = 0;
child.parent = node;
child.id = node.id + "/";
node.children.unshift(child);
}
});
const root = path != null ? stratify(data)
: id != null || parentId != null ? d3.stratify().id(id).parentId(parentId)(data)
: d3.hierarchy(data, children);
// Compute the values of internal nodes by aggregating from the leaves.
value == null ? root.count() : root.sum(d => Math.max(0, d ? value(d) : null));
// Prior to sorting, if a group channel is specified, construct an ordinal color scale.
const leaves = root.leaves();
const G = group == null ? null : leaves.map(d => group(d.data, d));
if (zDomain === undefined) zDomain = G;
zDomain = new d3.InternSet(zDomain);
const color = group == null ? null : d3.scaleOrdinal(zDomain, colors);
// Compute labels and titles.
const L = label == null ? null : leaves.map(d => label(d.data, d));
const T = title === undefined ? L : title == null ? null : leaves.map(d => title(d.data, d));
// Sort the leaves (typically by descending value for a pleasing layout).
if (sort != null) root.sort(sort);
// Compute the treemap layout.
d3.treemap()
.tile(tile)
.size([width - marginLeft - marginRight, height - marginTop - marginBottom])
.paddingInner(paddingInner)
.paddingTop(paddingTop)
.paddingRight(paddingRight)
.paddingBottom(paddingBottom)
.paddingLeft(paddingLeft)
.round(round)
(root);
const svg = d3.create("svg")
.attr("viewBox", [-marginLeft, -marginTop, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.attr("font-family", "sans-serif")
.attr("font-size", 10);
const node = svg.selectAll("a")
.data(leaves)
.join("a")
.attr("xlink:href", link == null ? null : (d, i) => link(d.data, d))
.attr("target", link == null ? null : linkTarget)
.attr("transform", d => `translate(${d.x0},${d.y0})`);
node.append("rect")
.attr("fill", color ? (d, i) => color(G[i]) : fill)
.attr("fill-opacity", fillOpacity)
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-opacity", strokeOpacity)
.attr("stroke-linejoin", strokeLinejoin)
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0);
if (T) {
node.append("title").text((d, i) => T[i]);
}
if (L) {
// A unique identifier for clip paths (to avoid conflicts).
const uid = `O-${Math.random().toString(16).slice(2)}`;
node.append("clipPath")
.attr("id", (d, i) => `${uid}-clip-${i}`)
.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0);
node.append("text")
.attr("clip-path", (d, i) => `url(${new URL(`#${uid}-clip-${i}`, location)})`)
.selectAll("tspan")
.data((d, i) => `${L[i]}`.split(/\n/g))
.join("tspan")
.attr("x", 3)
.attr("y", (d, i, D) => `${(i === D.length - 1) * 0.3 + 1.1 + i * 0.9}em`)
.attr("fill-opacity", (d, i, D) => i === D.length - 1 ? 0.7 : null)
.text(d => d);
}
return Object.assign(svg.node(), {scales: {color}});
}
);
export const shuffle = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
};
export const G12DU = (amount) => {
return (Math.round(amount / DU * 100) / 100);
};
export const query__expenses = (walletPk, size = 100) => {
return {
_source: ["amount", "recipient"]
,size: size
,query: {
bool: {
filter: [
{term: {"issuer": walletPk}}
]
}
}
};
};
export const fetchExpenses = async (pubkey, limit = 100) => {
shuffle(CESIUM_G1_NODES); // Mélanger la liste des noeuds
for (let node of CESIUM_G1_NODES) {
try {
const url = `${node}/g1/movement/_search`;
let queryBody = query__expenses(pubkey, limit);
console.log('expenses queryBody : \n', JSON.stringify(queryBody));
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(queryBody)
});
const data = await response.json();
console.log('node for the expenses of :\n', pubkey, '\n', node);
console.log('expenses data :\n', data);
let expensesByRecipient = {};
let totalAmount = 0;
for (const hit of data.hits.hits) {
const tx = hit._source;
if (!(tx.recipient in expensesByRecipient)) {
expensesByRecipient[tx.recipient] = 0;
}
expensesByRecipient[tx.recipient] += tx.amount/100;
totalAmount += tx.amount;
}
totalAmount = totalAmount/100;
return {
expensesTotalAmount: totalAmount
,expensesByRecipient: expensesByRecipient
};
} catch (error) {
console.error(`Failed to fetch data from ${node}: ${error}`);
// Si une erreur se produit, passez simplement au noeud suivant
}
}
throw new Error("Failed to fetch data from all nodes");
};
export const query__cesium_profile = (pubkey) => {
return {
_source: [
"title",
"issuer"
]
,query: {
bool: {
filter: [
{term: {"_type": "profile"}}
]
,should: [
{ term: { "issuer": pubkey } },
]
,minimum_should_match: 1
}
}
};
};
export const query__cesium_profiles = (pubkeys) => {
return {
_source: ["title"]
,query: {
bool: {
filter: [
{term: {"_type": "profile"}}
]
,should: [
...pubkeys.map(pk => ({ term: { "issuer": pk } })),
]
,minimum_should_match: 1
}
}
};
};
export const fetchCesiumProfile = async (pubkey) => {
shuffle(CESIUM_G1_NODES); // Mélanger la liste des noeuds
for (let node of CESIUM_G1_NODES) {
try {
const url = `${node}/user/profile/_search`;
let queryBody = query__cesium_profile(pubkey);
console.log('cesium_profile queryBody : \n', JSON.stringify(queryBody));
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(queryBody)
});
const data = await response.json();
if (data.hits.hits[0] == undefined) {
return null;
}
return data.hits.hits[0]._source;
} catch (error) {
console.error(`Failed to fetch data from ${node}: ${error}`);
// Si une erreur se produit, passez simplement au noeud suivant
}
}
throw new Error("Failed to fetch data from all nodes");
};
export const fetchCesiumProfiles = async (pubkeys) => {
shuffle(CESIUM_G1_NODES); // Mélanger la liste des noeuds
for (let node of CESIUM_G1_NODES) {
try {
const url = `${node}/user/profile/_search`;
let queryBody = query__cesium_profiles(pubkeys);
console.log('cesium_profiles queryBody : \n', JSON.stringify(queryBody));
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(queryBody)
});
const data = await response.json();
let profiles = [];
for (const hit of data.hits.hits) {
profiles[hit._id] = {
title: hit._source.title
};
}
return profiles;
} catch (error) {
console.error(`Failed to fetch data from ${node}: ${error}`);
// Si une erreur se produit, passez simplement au noeud suivant
}
}
throw new Error("Failed to fetch data from all nodes");
};
export const displayExpenses = (expensesByRecipient, expensesTotalAmount, recipientsCesiumProfiles, chartColors, currentPubkey, currentProfile) => {
let screenElt = document.querySelector('#expenses');
screenElt.innerHTML = '';
let currentProfileTitleElt = document.createElement('h2');
screenElt.append(currentProfileTitleElt);
let title = null;
if (currentProfile == undefined) {
title = 'Dépenses du portefeuille <code>' + currentPubkey.substr(0, 8) + '</code>';
} else {
title = 'Dépenses de <q>' + currentProfile.title + '</q>';
}
currentProfileTitleElt.innerHTML = title;
let svgContainer = document.createElement('article');
screenElt.append(svgContainer);
svgContainer.classList.add("svg-container");
let chartData = [];
// Formatting data
for (const recipient in expensesByRecipient) {
let recipientObj = {};
recipientObj.pk = recipient;
recipientObj.amount = expensesByRecipient[recipient];
let numberOptions = { roundingMode: 'ceil', minimumFractionDigits: 0, maximumFractionDigits: 0 };
recipientObj.displayedAmount = G12DU(recipientObj.amount).toLocaleString('fr-FR', numberOptions) + ' DU';
if (recipientsCesiumProfiles[recipient] != undefined
&& recipientsCesiumProfiles[recipient].title != undefined
) {
recipientObj.title = recipientsCesiumProfiles[recipient].title;
} else {
recipientObj.title = recipient.substr(0, 8);
}
chartData.push(recipientObj);
}
let chart = Treemap(chartData, {
path: d => d.title,
value: d => d.amount,
group: d => d.title,
label: (d, n) => d.title,
title: (d, n) => d.displayedAmount,
link: (d, n) => '#' + d.pk + '',
linkTarget: '_self',
tile: d3.treemapSquarify,
width: 1280,
height: 720,
padding: 0,
colors: chartColors,
fillOpacity: 1
});
svgContainer.append(chart);
screenElt.scrollIntoView({behavior: 'smooth'}, true);
};
let formElt = document.querySelector('form#explore');
const treemapIt = async (pubkey, maxNbTx = MAX_NB_TX) => {
let dotsPos = pubkey.indexOf(':');
if (dotsPos != -1) {
pubkey = pubkey.substr(0, dotsPos);
}
let { expensesTotalAmount, expensesByRecipient } = await fetchExpenses(pubkey, maxNbTx);
let recipientsList = Object.keys(expensesByRecipient);
let recipientsCesiumProfiles = await fetchCesiumProfiles(recipientsList);
let currentProfile = await fetchCesiumProfile(pubkey);
console.log('currentProfile :\n', currentProfile);
displayExpenses(expensesByRecipient, expensesTotalAmount, recipientsCesiumProfiles, chartColors, pubkey, currentProfile);
let svg = document.querySelector('#expenses svg');
let links = svg.querySelectorAll("a");
for (const link of links) {
link.addEventListener('click', (linkEvent) => {
// linkEvent.currentTarget.preventDefault();
console.log('linkEvent.currentTarget :\n', linkEvent.currentTarget);
let pubkey = linkEvent.currentTarget.getAttribute('href').substr(1);
treemapIt(pubkey);
});
}
};
formElt.addEventListener('submit', (formEvent) => {
formEvent.preventDefault();
let pubkey = formEvent.target.querySelector('input[name="pubkey"]').value;
let txLimit = formEvent.target.querySelector('input[name="txLimit"]').value;
treemapIt(pubkey, txLimit);
});

View File

@ -0,0 +1,43 @@
header {
text-align: center;
margin-bottom: 2rem;
}
header h1 {
margin-bottom: 0.5rem;
}
header #description {
margin-top: 0.5rem;
font-style: italic;
}
#expenses svg {
font-size: 24px !important;
}
form {
margin: auto;
}
footer {
margin-top: 3rem;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
margin-bottom: 3rem;
border-top: 2px solid hsl(0, 0%, 95%);
}
footer blockquote {
margin: 0;
font-style: italic;
text-align: center;
}

View File

@ -174,7 +174,8 @@ var earth3d;
$elem.appendTo(widget.options.locationsElement);
$elem.click(function() {
// alert('Clicked on ' + location.name + ' : ' + location.link );
window.open( location.link, "AstroTab");
// window.open( location.link, "AstroTab");
window.parent.location.href = location.link;
});
location.$element = $elem;
},

View File

@ -13,14 +13,22 @@
}
#coordinates-display {
position: absolute;
bottom: 10px; /* Adjust the bottom position as needed */
bottom: 20px; /* Adjust the bottom position as needed */
left: 10px; /* Adjust the left position as needed */
background-color: white;
padding: 5px;
border: 1px solid black;
z-index: 1000;
}
#map-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map-container" style="position: relative;">
@ -131,7 +139,7 @@ if (deg <= 0.01) {
container.style.height = '100vh';
container.style.backgroundColor = 'rgba(255, 255, 255, 0.4)';
container.style.border = 'none';
container.style.zIndex = '1000';
container.style.zIndex = '999';
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
@ -150,6 +158,7 @@ if (deg <= 0.01) {
button.addEventListener('click', () => {
const url = `http://astroport.localhost:1234/?uplanet=@&lat=${southWestLat}&lon=${southWestLon}`;
// const url = `https://astroport.copylaradio.com/?uplanet=@&lat=${southWestLat}&lon=${southWestLon}`;
window.location.href = url;
});

1
earth/nacl.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
earth/scrypt-async.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
nacl.min.js vendored Normal file

File diff suppressed because one or more lines are too long