fix search regexp escape,

wrap chartjs with custom element
This commit is contained in:
Arthur Lu 2023-10-04 18:59:46 +00:00
parent 9d832fea69
commit fb84ca5616
5 changed files with 78 additions and 53 deletions

View File

@ -9,6 +9,7 @@
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/nav.css"> <link rel="stylesheet" href="css/nav.css">
<script src="scripts/account.js" type="module"></script> <script src="scripts/account.js" type="module"></script>
<script src="scripts/chart.js" type="module"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style> <style>
@media screen and (width >= 1264px){ @media screen and (width >= 1264px){
@ -18,12 +19,6 @@
grid-gap: 0px; grid-gap: 0px;
justify-content: space-between; justify-content: space-between;
} }
#resource-container > * {
position: relative;
min-width: 200px;
max-width: 400px;
aspect-ratio: 1 / 1;
}
} }
@media screen and (width <= 1264px) and (width >= 480px) { @media screen and (width <= 1264px) and (width >= 480px) {
#resource-container { #resource-container {

View File

@ -43,68 +43,61 @@ function populateResources (containerID, meta, resources) {
if (meta[resourceType].display) { if (meta[resourceType].display) {
if (meta[resourceType].type === "list") { if (meta[resourceType].type === "list") {
resources[resourceType].forEach((listResource) => { resources[resourceType].forEach((listResource) => {
const chart = createResourceUsageChart(listResource.name, listResource.avail, listResource.used, listResource.max, null); createResourceUsageChart(container, listResource.name, listResource.avail, listResource.used, listResource.max, null);
container.append(chart);
}); });
} }
else { else {
const chart = createResourceUsageChart(meta[resourceType].name, resources[resourceType].avail, resources[resourceType].used, resources[resourceType].max, meta[resourceType]); createResourceUsageChart(container, meta[resourceType].name, resources[resourceType].avail, resources[resourceType].used, resources[resourceType].max, meta[resourceType]);
container.append(chart);
} }
} }
}); });
} }
} }
function createResourceUsageChart (resourceName, resourceAvail, resourceUsed, resourceMax, resourceUnitData) { function createResourceUsageChart (container, resourceName, resourceAvail, resourceUsed, resourceMax, resourceUnitData) {
const container = document.createElement("div"); const chart = document.createElement("custom-chart");
const canvas = document.createElement("canvas"); container.append(chart);
container.append(canvas);
const maxStr = parseNumber(resourceMax, resourceUnitData); const maxStr = parseNumber(resourceMax, resourceUnitData);
const usedStr = parseNumber(resourceUsed, resourceUnitData); const usedStr = parseNumber(resourceUsed, resourceUnitData);
const usedRatio = resourceUsed / resourceMax; const usedRatio = resourceUsed / resourceMax;
const R = Math.min(usedRatio * 510, 255); const R = Math.min(usedRatio * 510, 255);
const G = Math.min((1 - usedRatio) * 510, 255); const G = Math.min((1 - usedRatio) * 510, 255);
const usedColor = `rgb(${R}, ${G}, 0)`; const usedColor = `rgb(${R}, ${G}, 0)`;
createChart(canvas, { chart.data = {
type: "pie", chart: {
data: { type: "pie",
labels: [ data: {
"Used", labels: [
"Available" "Used",
], "Available"
datasets: [{
label: resourceName,
data: [resourceUsed, resourceAvail],
backgroundColor: [
usedColor,
"rgb(140, 140, 140)"
], ],
borderWidth: 0, datasets: [{
hoverOffset: 4 label: resourceName,
}] data: [resourceUsed, resourceAvail],
}, backgroundColor: [
options: { usedColor,
plugins: { "rgb(140, 140, 140)"
title: { ],
display: true, borderWidth: 0,
position: "bottom", hoverOffset: 4
text: [resourceName, `Used ${usedStr} of ${maxStr}`], }]
color: "white" },
}, options: {
legend: { plugins: {
display: false title: {
display: true,
position: "bottom",
text: [resourceName, `Used ${usedStr} of ${maxStr}`],
color: "white"
},
legend: {
display: false
}
} }
} }
} },
}); ariaLabel: `${resourceName} used ${usedStr} of ${maxStr}`
canvas.role = "img"; };
canvas.ariaLabel = `${resourceName} used ${usedStr} of ${maxStr}`;
return container;
}
function createChart (ctx, data) {
return new window.Chart(ctx, data);
} }
function parseNumber (value, unitData) { function parseNumber (value, unitData) {

35
scripts/chart.js Normal file
View File

@ -0,0 +1,35 @@
class CustomChart extends HTMLElement {
constructor (data) {
super();
this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = `
<style>
div {
min-width: 200px;
max-width: 400px;
aspect-ratio: 1 / 1;
}
</style>
<div>
<canvas>
</div>
`;
this.canvas = this.shadowRoot.querySelector("canvas");
}
set data (data) {
this.canvas.role = "img";
this.canvas.ariaLabel = data.ariaLabel;
createChart(this.canvas, data.chart);
}
get data () {
return null;
}
}
function createChart (ctx, data) {
return new Chart(ctx, data);
}
customElements.define("custom-chart", CustomChart);

View File

@ -5,7 +5,7 @@ const draggableItemUUIDs = {};
* Get the data transfer source object by parsing its types. Valid draggable-item events have one type of the format `application/json/${uuid}`. * Get the data transfer source object by parsing its types. Valid draggable-item events have one type of the format `application/json/${uuid}`.
* The function takes the entire type list from event.dataTransfer.types and returns the source object if valid, or null if invalid. * The function takes the entire type list from event.dataTransfer.types and returns the source object if valid, or null if invalid.
* @param {*} typesList from event.dataTransfer.types * @param {*} typesList from event.dataTransfer.types
* @returns {Object} Object containing the type, uuid, and element of the dataTransfer source or null * @returns {Object} Object containing the type, uuid, and element of the dataTransfer source or null
*/ */
function getDragSource (typesList) { function getDragSource (typesList) {
if (typesList.length !== 1) { if (typesList.length !== 1) {

View File

@ -77,8 +77,10 @@ class InstanceCard extends HTMLElement {
const nameParagraph = this.shadowRoot.querySelector("#instance-name"); const nameParagraph = this.shadowRoot.querySelector("#instance-name");
if (this.searchQuery) { if (this.searchQuery) {
const regEscape = v => v.replace("[-[\]{}()*+?.,\\^$|#\s]", "\\$&"); const regExpEscape = v => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const nameParts = this.name.split(new RegExp(regEscape(`(${this.searchQuery})`), "ig")); const escapedQuery = regExpEscape(this.searchQuery);
const searchRegExp = new RegExp(`(${escapedQuery})`, "gi");
const nameParts = this.name.split(searchRegExp);
for (let i = 0; i < nameParts.length; i++) { for (let i = 0; i < nameParts.length; i++) {
const part = document.createElement("span"); const part = document.createElement("span");
part.innerText = nameParts[i]; part.innerText = nameParts[i];