Skip to content

Instantly share code, notes, and snippets.

@Rinidh
Last active February 8, 2025 14:08
Show Gist options
  • Save Rinidh/60ea73d4285acf1364d1bb96b2bea6ef to your computer and use it in GitHub Desktop.
Save Rinidh/60ea73d4285acf1364d1bb96b2bea6ef to your computer and use it in GitHub Desktop.
js-code #code-only
/**
This file accesses all HTMLCanvasElement instances on the page/DOM, and applies a 50-unit grid, easily visible dark and light modes
Prefer to call this script at the end of all canvas renderings or after all other scripts to prevent hiding of grids behind drawings
*/
const canvases = document.querySelectorAll('canvas');
function drawGrids() {
//log cleaner, concise console error about no canvases detected
try {
canvases[0].getContext
} catch (err) {
if (err.message.includes("Cannot read properties of undefined (reading 'getContext')"))
return console.warn("canvasGrid: No canvases seen on the page!")
}
if (canvases[0].getContext) { //if canvas has a meth to get 2D context ie if the browser supports canvas API
canvases.forEach((canvas) => {
const ctx = canvas.getContext("2d")
const theme = getTheme()
//defaults & adjustments
canvas.style.backgroundColor = theme === "dark" ? "rgb(55, 55, 55)" : "rgb(248, 248, 248)"
ctx.fillStyle = theme === "dark" ? 'white' : 'black'
ctx.font = "0.7rem calibri"
ctx.textAlign = 'center'
ctx.strokeStyle = theme === "dark" ? '#f5f5f5' : '#5c5c5c'
ctx.lineWidth = 0.5;
ctx.setLineDash([3, 5])
const canvasWidth = canvas.clientWidth
const canvasHeight = canvas.clientHeight
const startPoint = 0
//clear canvas
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
//horizontal lines (varyingCoordinate is y)
let endPoint = canvasWidth
for (let varyingCoordinate = 50.5; varyingCoordinate < canvasHeight; varyingCoordinate += 50) { //varyingCoordinate is xxx.5 for crisp lines
ctx.beginPath()
ctx.moveTo(startPoint, varyingCoordinate)
ctx.lineTo(endPoint, varyingCoordinate)
ctx.stroke()
//coordinate label
ctx.fillText(`${varyingCoordinate - 0.5}`, 10, varyingCoordinate + 10)
ctx.fillText(`${varyingCoordinate - 0.5}`, canvasWidth - 15, varyingCoordinate + 10)
}
//vertical lines (varyingCoordinate is x)
endPoint = canvasHeight
for (let varyingCoordinate = 50.5; varyingCoordinate < canvasWidth; varyingCoordinate += 50) {
ctx.beginPath()
ctx.moveTo(varyingCoordinate, startPoint)
ctx.lineTo(varyingCoordinate, endPoint)
ctx.stroke()
//coordinate label
ctx.fillText(`${varyingCoordinate - 0.5}`, varyingCoordinate + 3, 10)
ctx.fillText(`${varyingCoordinate - 0.5}`, varyingCoordinate + 3, canvasHeight - 6)
}
})
}
}
drawGrids() //initial call
function getTheme() {
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
console.log('dark')
return "dark"
} else {
console.log('light')
return "light"
}
}
// observe & adapt to theme changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", drawGrids) //redraw the grids (whoch internally again fetch the new theme and apply colors)
// NORMAL fetch() DEMO:
// fetch("https://jsonplaceholder.typicode.com/posts?_limit=3")
// .then(res =>
// res.json()
// )
// .then(data =>
// console.log(data)
// )
// .catch(err =>
// console.error(err)
// )
//no need for 'for await...of' if iterable is normal array instead of async *func (generators) or Promise
async function getResults(...resultsIds) {
for (let id of resultsIds) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
const data = await res.json()
console.log(data)
}
}
getResults(1, 3, 10)
//use 'for await...of' if async iterable or async *func (gen func):
const LIMIT = 3
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0
return {
next() {
const value = i
const done = i === LIMIT
i++;
return Promise.resolve({ value, done }) //each next() call returns an async value that's awaited for before being assigned to block scoped variable 'val' in the loop
},
return() { //if 'break' in btn
return { done: true }
}
}
}
}
async function run() {
for await (const val of asyncIterable) {
console.log(val)
}
}
run()
//A CUSTOM ITERATOR
function funcThatReturnsIteratorObj(start, finish) {
let index = start;
let count = 0;
return {
next() {
let result;
if (index < finish) {
result = { value: index, done: false }
index += 1;
count++;
return result;
}
return {
value: count,
done: true
}
}
}
}
const it = funcThatReturnsIteratorObj(0, 10);
let res = it.next();
while (!res.done) {
console.log(res.value);
res = it.next();
}
//A CUSTOM ITERABLE
let idx = 0;
const myIterable = {
[Symbol.iterator]() {
return {
[Symbol.iterator]() { return this; },//to make the obj an "iterable". May or may not be put
next() {
const current = idx;
idx++;
if (current <= 3) {
return { value: current, done: false };
} else {
return { value: current, done: true };
}
}
}
}
}
for (let val of myIterable) {//the for...of loop is designed defaultly to run the [Sym.itr]() method of the iterable(myIterable) and access the return obj (the iterator) with the next() method
//and call it again and again until done is true
//val here is set, by the for..of loop, to the value prop of the obj returned by next() method again and again until done is true
console.log(val);
}
//A GEN FUNC THAT RUNS FOREVER, RETURNING AN OBJ WITH THE VALUE PROP HOLDING A RANDOM NUM
function* randomNum() {
while (true) {
yield Math.floor(math.randomNum() * 100)
}
}
let it = randomNum()
console.log(it.next())
console.log(it.next())
/*
//FIND WHAT THIS DOES IN NODE
const CAF = require("caf")
const jsonServer = require("json-server")
const server = jsonServer.create()
const router = jsonServer.router("src/db.json")
const middlewares = jsonServer.defaults()
server.use(middlewares)
server.use(router)
server.listen(3000, ()=>{
console.log("json server is running!")
})
*/
//CAFs
const CAF = require("caf")
const token = new CAF.cancelToken()
//const token2 = new CAF.timeout(300, "This message will display after 300 millisecs of waiting by the timeout token")
//the above timeout token will cancel/abort the fetchCAF func and the CAF.delay setTimeOut() within after 3 secs
const fetchCAF = CAF(function* fetchData(signal) {
CAF.delay(signal, 400)//to simulate or act as a time consuming process of 4 secs
const promise = yield axios.get("http://localhost:3000/users")
return promise;
})
fetchCAF(token.signal).then(res => { console.log(res.data) })//gives errors
//fetchCAF(token).then(res => {console.log(res.data)})//use token instead of token.signal to canel even the CAF.delay() inside
// This file contains general js functions, classes etc for reference
//HELPER/UTILITY FUNCTIONS:
function reverseWords(sentence) {
//get array of indices of spaces
const indicesOfSpaces = Array.from(SENTENCE).map((character, index) => {
return character === " " ? index : null
})
const indicesOfSpaces_AllTruthy = indicesOfSpaces.filter(Boolean)
//get array of sentence's words only
let wordsArray = [];
let startIndex = 0;
indicesOfSpaces_AllTruthy.forEach((endIndex) => {
const word = SENTENCE.substring(startIndex, endIndex)
wordsArray.push(word)
startIndex = endIndex + 1
})
const lastWord = SENTENCE.substring(startIndex)
wordsArray.push(lastWord)
//OR
const wordsArray2 = SENTENCE.split(" ")
wordsArray2
//get array of words in reversed order
let wordsArrayReversed = []
for (let index = wordsArray2.length - 1; index > -1; index--) {
wordsArrayReversed.push(wordsArray2[index])
}
wordsArrayReversed
//join into string with spaces again
const reversedSentence = wordsArrayReversed.join(" ")
// return reversedSentence
// OR EASIER:
// return sentence.split(" ").reverse().join(" ")
}
function escapeHTML(strings, ...values) {
const replaceSpecialChars = (str) => { //helper func
return str.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
const safeString = strings.reduce((accumulatedResultString, currentStringPart, i) => { //hacker's text comes in values array
return accumulatedResultString +
currentStringPart +
(values[i] ? replaceSpecialChars(String(values[i])) : "")
}, "")
return safeString
}
// const userInput = "<script>alert('hacker's message!') //or other malicious code</script>" //if browser parses this raw string, the js script may run
// const res = escapeHTML`Hacker input: ${userInput}`
function formatWithCommas(strings, ...values) {
function putCommas(value) {
if (typeof value === "number") return value.toLocaleString()
}
const formattedString = strings.reduce((accumulatedString, currentString, index) => {
return accumulatedString + currentString + (putCommas(values[index]) || "")
}, "")
return formattedString;
}
// console.log(formatWithCommas`your qty is ${1234} and bill $${23000} e`)
function canvasGrid(canvas) { //add more fucntionality like stroke width, gap, color, numbers etc
if (canvas.getContext) {
const ctx = canvas.getContext("2d")
//defaults
ctx.shadowOffsetX = 0
ctx.shadowOffsety = 0
ctx.shadowBlur = 0
ctx.shadowColor = 'rgb(0 0 0 /0%)'
ctx.fillStyle = 'black'
ctx.strokeStyle = '#5c5c5c'
ctx.lineWidth = 0.5;
ctx.setLineDash([3, 5])
const canvasWidth = canvas.clientWidth
const canvasHeight = canvas.clientHeight
const startPoint = 0
//horizontal lines (varyingCoordinate is y)
let endPoint = canvasWidth
for (let varyingCoordinate = 50.5; varyingCoordinate < canvasHeight; varyingCoordinate += 50) { //varyingCoordinate is xxx.5 for crisp lines
ctx.beginPath()
ctx.moveTo(startPoint, varyingCoordinate)
ctx.lineTo(endPoint, varyingCoordinate)
ctx.stroke()
//coordinate label
ctx.font = "0.7rem calibri"
ctx.fillText(`${varyingCoordinate - 0.5}`, 3, varyingCoordinate + 10)
ctx.fillText(`${varyingCoordinate - 0.5}`, canvasWidth - 25, varyingCoordinate + 10)
}
//vertical lines (varyingCoordinate is x)
endPoint = canvasHeight
for (let varyingCoordinate = 50.5; varyingCoordinate < canvasWidth; varyingCoordinate += 50) {
ctx.beginPath()
ctx.moveTo(varyingCoordinate, startPoint)
ctx.lineTo(varyingCoordinate, endPoint)
ctx.stroke()
ctx.font = "0.7rem calibri"
ctx.fillText(`${varyingCoordinate - 0.5}`, varyingCoordinate + 3, 10)
ctx.fillText(`${varyingCoordinate - 0.5}`, varyingCoordinate + 3, canvasHeight - 6)
}
}
//SEE ADVANCED FORM of this in the GIST: js-code/canvasGrid.js
}
function roundedRect(ctx, x, y, width, height, radius) { // A utility function to draw a rectangle with rounded corners.
ctx.beginPath();
ctx.moveTo(x, y + radius);
ctx.arcTo(x, y + height, x + radius, y + height, radius);
ctx.arcTo(x + width, y + height, x + width, y + height - radius, radius);
ctx.arcTo(x + width, y, x + width - radius, y, radius);
ctx.arcTo(x, y, x, y + radius, radius);
ctx.stroke();
}
const winston = require("winston");
const logger = winston.createLogger({
level: "verbose", //messages with level verbose or higher can be logged with this 'logger' instance. logger.verbose() won't work
format: winston.format.json(), //others:
defaultMeta: { service: "eg user-service" }, //appears in all logs as end-messages
transports: [
new winston.transports.File({
filename: "warnOrHigher.log",
level: "warn", // warn or higher level msgs
}),
new winston.transports.File({ filename: "combined.log" }), //all logs that are logged with this 'logger' ie all logs that are level verbose or higher
new winston.transports.Console({
format: winston.format.simple(),
}),
],
});
logger.error("error lvl"); //goes into both warnOrHigher.log and combined.log
logger.info("info lvl"); //goes into only combined.log
logger.silly("silly lvl"); //doesn't work
//NOTES
//LEVELS
// error: 0,
// warn: 1,
// info: 2,
// http: 3,
// verbose: 4,
// debug: 5,
// silly: 6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment