zoomdata.js A JavaScript library to help making thinks zoomable
<script src="https://auer404.github.io/zoomdata-js/zoomdata.js"></script>

Basic usage :

HTML

<div id="container">
    <div id="child"></div>
</div>

CSS

#container {
    position:relative; 
    overflow:hidden; user-select:none;
    /* + width, height */
}

#child {
    position:absolute;
}

JS

let zd = create_zoomdata( document.querySelector("#container") );

let child = document.querySelector("#child");

zd.register_object({
    attach_to: child,
    x: 100,
    y: 100,
    width: 200,
    height: 200
});

zd.onupdate = function(){
    child.style.left = child.zoomdata.x + "px";
    child.style.top = child.zoomdata.y + "px";
    child.style.width = child.zoomdata.width + "px";
    child.style.height = child.zoomdata.height + "px";
} // will be fired after every zoom or move...

// ...but should be called manually to "draw" the initial state :
zd.onupdate();
#container
(mousewheel to zoom, drag around once zoomed)
#child

Using percent units :

CSS

#child {
    position:absolute;
    transform:translateY(-50%);
    aspect-ratio:1/1;
}

JS

zd.register_object({
    attach_to: child,
    x: "25%",
    y: "50%",
    width: "50%"
});

zd.onupdate = function(){
    child.style.left = child.zoomdata.percent.x + "%";
    child.style.top = child.zoomdata.percent.y + "%";
    child.style.width = child.zoomdata.percent.width + "%";
}
centered, 1/2 container width

Registering unattached objects :

HTML

<canvas id="container"></canvas>

JS

let ctx = document.querySelector("#container").getContext("2d");
ctx.fillStyle = "#CCC";
ctx.strokeStyle = "#FFF";

let zd = create_zoomdata( document.querySelector("#container") );

let child_zd = zd.register_object({
    x: "25%",
    y: "50%",
    width: "50%"
});

zd.onupdate = function(){

    ctx.fillRect(0 , 0 , ctx.canvas.width , ctx.canvas.height);

    ctx.strokeRect(
        child_zd.x,
        child_zd.y - child_zd.width / 2,
        child_zd.width,
        child_zd.width
    );

}

Zoom-factor-based modifications :

CSS

.child {
    border-width:3px;
    font-size:15px;
    position:absolute;
    transform:translateY(-50%);
    aspect-ratio:1/1;
}

JS

let children = document.querySelectorAll("#container .child");
            
zd.register_object({
    attach_to: children[0],
    x: "37.5%",
    y: "40%",
    width: "25%"
});

zd.register_object({
    attach_to: children[1],
    x: "37.5%",
    y: "60%",
    width: "25%"
});

zd.onupdate = function(){

    for (child of children) {
        child.style.left = child.zoomdata.percent.x + "%";
        child.style.top = child.zoomdata.percent.y + "%";
        child.style.width = child.zoomdata.percent.width + "%";
    }

    children[1].style.borderWidth = children[1].zoomdata.zoomed(3) + "px";
    children[1].style.fontSize = children[1].zoomdata.zoomed(15) + "px";

}
position / dimensions only
complete zoom effect

More to come

Doc under construction

Options : create_zoomdata()

// Default values for (optional) second argument

create_zoomdata(
    target_HTML_element,
    {
        max_zoomfactor: 2, // number > 1
        auto_drag_cursor: false, // true / false
        auto_zoom_cursor: false, // true / false
        zoom_key: false, // string key or keycode / false
        drag_key: false, // string key or keycode / false
        allow_drag: true, // true / false
        auto_update_objects: true, // true / false
        zoom_on_mousewheel: true, // true / false
        mouse_based_zoom_origin: true, // true / false
        prevent_scroll_on_mousewheel: true // true / "always" / false
    }
);