elem.showNote()

🔰 JSbrowserDOMtypesElementbounding rect ⟩ elem.showNote()

💾 replit: elem.showNote() - show note beside element.

const { log } = console;

// ⭐️ select element
function $(selector, parent = document) {
    return parent.querySelector(selector);
}

// ⭐️ newElement()
/*
 * create and configure a new Element
 * 
 * @param {string} tagName  - like 'div', 'span' ...
 * @param {function} config - function to configure the newly created element
 * @return {Element}
 */
function newElement(tagName, config) {
    let elem = document.createElement(tagName);
    if (config) { config(elem) }
    return elem;
}

// ------------- extending Element -------------

// 🔸 elem.anchorPositionFor()
/*
 * calculate the "anchor" point for the "note" element
 * 
 * @param {Element} noteElem - the "note" element to be put aside
 * @param {string} position  - top | right | bottom (default)
 * @return {object}          - x, y coords relative to viewport
 *
 * 🧨 warning: 
 *    two elements (`this` and `noteElem`) must be in the document
 *    before calling `getBoundingClientRect()`❗
 */
Element.prototype.anchorPositionFor = function(noteElem, position = 'bottom') {

    const { x: x1, y: y1, width: w1, height: h1 } = this.getBoundingClientRect();
    const { width: w2, height: h2 } = noteElem.getBoundingClientRect();

    switch (position) {
        case 'top'   : return { x: x1     , y: y1 - h2 };
        case 'right' : return { x: x1 + w1, y: y1      };
        case 'bottom': return { x: x1     , y: y1 + h1 };
        default: return { x: x1, y: y1 + h1 };            // default = 'bottom'
    }
};

// 🔸 elem.showNote()
Element.prototype.showNote = function(html, position='bottom') {
    const _ = newElement('div', (elem)=>{
        elem.innerHTML = html;
        elem.classList.add('note');
        
        // ⭐ must add to DOM before getting its bounding rect
        document.body.append(elem); 
        
        const {x, y} = this.anchorPositionFor(elem, position);
        elem.style.left = x + 'px';
        elem.style.top = y + 'px';
    });
};

// ------------- main -------------

const info = $('#scrollInfo');

$('#span1').showNote('hello world', 'top');
$('#span2').showNote('hello world');

// scroll handler
window.onscroll = (event) => {
    info.innerText = `scrollX: ${scrollX}, scrollY: ${scrollY}`;
};

// ------------- class Vector (not used) -------------
class Vector {

    // init
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // u.add(v): u + v
    add(v) {
        return new Vector(this.x + v.x, this.y + v.y)
    }

    // u.inverse(): -u
    inverse() {
        return new Vector(-this.x, -this.y);
    }

    // u.minus(v): u - v
    minus(v) {
        return this.add(v.inverse());
    }

    // toString
    toString() {
        return `(${this.x}, ${this.y})`
    }
}

Last updated