I need help making a zooming function

Joined
Dec 14, 2021
Messages
28
Reaction score
2
Well, I am trying to make a zooming function so that you could zoom in and out of the canvas, my HTML is:

HTML:
<!DOCTYPE html>
<html>
    <head>
        <meta name="build-version" content="V00.001.00" />
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="apple-mobile-web-app-capable" content="no"/>
        <title>Mapper Tool</title>
        <link href="style.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <h1>Mapper Tool</h1>
        <p style="text-align:center;">
            <label style="font-size:20px;" for="zoom">Zoom (Currently: <span id="currentZoom">100%</span>):</label>
            <br>
            25%<input type="range" name="zoom" id="zoom" min="25" max="500" defaultValue="100" value="100" step="5" onchange="zoom('change')">500%
            <br>
            <button id="zoomReset" onclick="zoom('reset')">Zoom Reset</button>
        </p>
        <div id="mapContainer">
            <div id="mapCur">
                <canvas id="mapDrawer" width="6000" height="6000">Your browser does not support the canvas element.</canvas>
                <!--<iframe src="map/map.html" title="The Map" width="6000" height="6000"></iframe>-->
            </div>
        </div>
        <!-- non-resource JS files -->
        <script src="map/map.js"></script>
        <script src="script.js"></script>
    </body>
</html>

My JavaScript is:

map.js:

JavaScript:
var canvas = document.getElementById("mapDrawer");
var ctx = canvas.getContext("2d");
ctx.moveTo(3000,0);
ctx.lineTo(3000,10);
ctx.stroke();

script.js:

JavaScript:
function getRndInteger(min, max) {
  return Math.floor(Math.random() * (max - min + 1) ) + min;
}

function setCookie(cname, cvalue) {
    document.cookie = cname + "=" + cvalue + ";";
}

function getCookie(cname) {
    let name = cname + "=";
    let ca = document.cookie.split(';');
    for(let i = 0; i < ca.length; i++) {
        let c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

/* -------------------------------------------------------------------------------- */

function zoom(type) {
    var zoomSlider = document.getElementById("zoom");
    var currentZoom = document.getElementById("currentZoom");
    var mapCur = document.getElementById("mapCur");
    if (type == "change") {
        mapCur.style.transform = "scale(" + (zoomSlider.value/100) + "," + (zoomSlider.value/100) + ")";
        currentZoom.innerHTML = zoomSlider.value + "%";
    } else if (type == "reset") {
        zoomSlider.value = 100;
        currentZoom.innerHTML = zoomSlider.value + "%";
    }
}
zoom("change");

My CSS is:

CSS:
/* elements */

body {
    overflow-x: hidden;
}

button {
    font-size: 1.171303074670571vw; /* 16px */
    cursor: pointer;
}

p {
    font-size: 1.171303074670571vw; /* 16px */
}

span {
    font-size: 1.171303074670571vw; /* 16px */
}

a {
    font-size: 1.171303074670571vw; /* 16px */
    text-decoration: none;
}

img {
    width: 100%;
    pointer-events: none;
}

iframe:focus {
  outline: none;
}

iframe[seamless] {
  display: block;
}

/* Headers */

h1, h2, h3, h4, h5, h6 {
    text-align: center;
}

h1 {
    font-size: 7.320644216691069vw; /* 80  100px */
}

h2 {
    font-size: 5.856515373352855vw; /* 40   80px */
}

h3 {
    font-size: 4.392386530014641vw; /* 30   60px */
}

h4 {
    font-size: 2.9282576866764276vw; /* 20   40px */
}

h5 {
    font-size: 1.4641288433382138vw; /* 18    20px */
}

h6 {
    font-size: 1.171303074670571vw; /* 16px */
}

/* footer -/||\- header */

header {
    display: block;
    text-align: center;
    /*padding: 0.21961932650073207vw; 3px*/
}

footer {
    display: block;
    padding: 1.4641288433382138vw; /* 20px */
    background: black;
    color: white;
    overflow-x: hidden;
    position: absolute;
    left: 0;
    width: 100%;
    /*
    position: relative;
    bottom: 0;
    width: 100%;
    */
}

#footSpacer {
    height: 16.837481698389457vw; /* 230px */
}

#footBtns {
    display: none;
    text-align: center;
}

#footContent {
    text-align:center;
}

/* -------------------------------------------------------------------------------- */

.hrSeps {
    border: 1px solid black;
    width: 100%;
    position: absolute;
    left: 0;
}

.ss {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
}

.buttons {
    text-align: center;
}

.hiddenTab {
    visibility: hidden;
    position: absolute;
}

.tabs {
    text-align: center;
}

.tab {
    background-color: #008CBA; /* Blue */
    border: none;
    color: white;
    padding: 1.171303074670571vw 2.342606149341142vw; /* 16px 32px */
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 1.171303074670571vw; /* 16px */
    /*margin: 4px 2px;*/
    transition-duration: 0.4s;
    cursor: pointer;
}

.style-tab1 {
    background-color: white;
    color: black;
    border: 2px solid #008CBA;
}

.style-tab1:hover {
    background-color: #008CBA;
    color: white;
}

.styletab1-active, .style-tab1:active {
    background-color: #ff7398;
    color: black;
    border: 0.14641288433382138vw solid #ff7398; /* 2px */
}

.style-tab2 {
    background-color: white;
    color: black;
    border: 0.14641288433382138vw solid #ff0043; /* 2px */
}

.style-tab2:hover {
    background-color: #ff0043;
    color: white;
}

.pbtnU {
    font-size: 1.4641288433382138vw; /* 20px */
}

.btnU {
    background-color: #ff0043;
    border: 0.29282576866764276vw solid #ff7398; /* 4px */
    color: white;
    padding: 0.8784773060029283vw 2.049780380673499vw; /* 16px 32px     12px 28px */
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 1.4641288433382138vw; /* 16px   20px */
    /*margin: 4px 2px;*/
    transition-duration: 0.4s;
    cursor: pointer;
}

.btnU:hover {
    background-color: #ff7398;
    border: 0.29282576866764276vw solid #ff0043; /* 4px */
    color: black;
}

.imgCenter {
    display: block;
    margin-left: auto;
    margin-right: auto;
}

.clearfix::after {
  content: "";
  clear: both;
  display: table;
}

.centerTxt {
    text-align: center;
}

.pre {
    font-family: monospace;
}

.pre p {
    font-weight: bold;
    white-space: pre;
    margin: 1.171303074670571vw 0; /* 1em // 16px */
}

/* -------------------------------------------------------------------------------- */

#currentZoom {
    font-size: 16px;
}

#zoom {
    width: 73.20644216691069vw; /* 1000px */
}

#zoomReset {
    font-size: 16px;
}

#mapContainer {
    overflow: scroll;
    width: 99.38%;
    height: 99.38%;
    position: absolute;
    left: 0;
    border: 4px solid #c3c3c3;
}

#mapDrawer {
    width: 6000px;
    height: 6000px;
}

I just can't seem to make a function that actually zooms in without making the little test line disappear, I what it to increase in size when you zoom in and I want it to decrease in size when you zoom out without it changing the actual quality of the thing. I would really like some help.
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
Sorry, I swear I'm not inept. I don't see anything but a huge white box (with no test line). What might I be doing wrong? I'd also suggest that we start with a smaller canvas and an actual image in the map (I'd recommend Blue Marble, barring any preference).
 
Joined
Dec 14, 2021
Messages
28
Reaction score
2
Sorry, I swear I'm not inept. I don't see anything but a huge white box (with no test line). What might I be doing wrong? I'd also suggest that we start with a smaller canvas and an actual image in the map (I'd recommend Blue Marble, barring any preference).
Well, the test line is in the top center of the canvas, so you would have to scroll a bit, but you could always just move the location that the test line is. Also, the canvas is so large because I want there to be enough space for a map to be drawn, as I will eventually get around to making it so that you can actually draw on the canvas, but first I just need to make it so that I can make it zoom in and out. Also, if you do this:

JavaScript:
var canvas = document.getElementById("mapDrawer");
var ctx = canvas.getContext("2d");
ctx.moveTo(300,0);
ctx.lineTo(300,10);
ctx.stroke();

to map.js then you would see the test line. You could even make the test line longer by changing the number 10 in ctx.lineTo(), to a bigger number if you want.
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
Ah, found it. The test line isn't outright disappearing, it's being shifted up and right out of frame with each consecutive zoom. Try adding the following to your style.css:

CSS:
#mapCur {
    transform-origin: 0 0;
}
 
Joined
Dec 14, 2021
Messages
28
Reaction score
2
Ah, found it. The test line isn't outright disappearing, it's being shifted up and right out of frame with each consecutive zoom. Try adding the following to your style.css:

CSS:
#mapCur {
    transform-origin: 0 0;
}
Thank you, this fixed the problem of it disappearing when you zoom in.

Now, I just need to find how to make it so that the quality doesn't decrease when you zoom in (which might not be possible) and make it so that the test line doesn't move when you zoom in/out. Basically, I want it so that you don't need to scroll to find the object that is in the canvas when you zoom in/out, meaning it would auto-scroll so that it is focused on the content that is in the current field of view that you are physically looking at.
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
Keeping the object in frame shouldn't be TOO hard. You'll likely need to calculate how much it'll move by using the difference in zoom and the size of the image/frame.

The quality is a different, much more difficult beast, but a much more fun one. I can't speak for stuff the canvas object paints, but I can for the map you're zooming around. The way GIS programs zoom in and out of arbitrarily huge maps is by using a raster pyramid, which is really a set of images of different sizes. When you zoom in further, you get the larger and larger, higher quality image. To prevent users from having to download the entire image (which could be hundreds of megs for science data), it's tiled up and the viewer attempts to only download what it's going to display. For more info on that, Google map servers and/or web map service.

If this is purely academic, have at it. If this solution needs to scale, I'd recommend using mapping library that can talk to a WMTS, set up your own map service with your custom map images, and let the library do its thing. It's likely easier to extend those to draw on rather than creating the mapping part.
 
Joined
Dec 14, 2021
Messages
28
Reaction score
2
Keeping the object in frame shouldn't be TOO hard. You'll likely need to calculate how much it'll move by using the difference in zoom and the size of the image/frame.

The quality is a different, much more difficult beast, but a much more fun one. I can't speak for stuff the canvas object paints, but I can for the map you're zooming around. The way GIS programs zoom in and out of arbitrarily huge maps is by using a raster pyramid, which is really a set of images of different sizes. When you zoom in further, you get the larger and larger, higher quality image. To prevent users from having to download the entire image (which could be hundreds of megs for science data), it's tiled up and the viewer attempts to only download what it's going to display. For more info on that, Google map servers and/or web map service.

If this is purely academic, have at it. If this solution needs to scale, I'd recommend using mapping library that can talk to a WMTS, set up your own map service with your custom map images, and let the library do its thing. It's likely easier to extend those to draw on rather than creating the mapping part.
Thanks, This is just a fun little mapping program that would allow you to make a map, meaning the map will be empty when you open the program and you make the map by either choosing the option of drawing it or moving around with the app open, basically it is just an academic purpose, but not much of academic, as after I make a working prototype I will upload it to Itch.io as an in-browser app, after I perfect the prototype I will translate it to work on Android, IOS and any other operating systems that are for mobile devices, as the fact is, this program would be best suited on mobile and not on PC as I will need to use location data for the second option.
I really love doing these things, making programs, also everything that I know about coding I had to learn from the internet, I self-taught myself.
I really love you for helping me out like this.
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
That sounds like a neat project, I look forward to watching it grow. If you get stuck or need some inspiration on the drawing and storing of maps, check out WBO, an open source, collaborative whiteboard. I'm not sure if they're using the same canvas mechanisms you are, though, so it may or may not translate well.
 
Joined
Dec 14, 2021
Messages
28
Reaction score
2
That sounds like a neat project, I look forward to watching it grow. If you get stuck or need some inspiration on the drawing and storing of maps, check out WBO, an open source, collaborative whiteboard. I'm not sure if they're using the same canvas mechanisms you are, though, so it may or may not translate well.
So is this link to the WBO collaborative whiteboard and is this link to the source code of the WBO collaborative whiteboard?
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
Yep, that's the one. It was pretty fun to tinker with, I set it up on my servers with Jitsi and Etherpad.
 
Joined
Mar 3, 2021
Messages
240
Reaction score
30
Try changing your zoom function to the following. I think I've got the math figured out. I calculate the center of the current scrollbars, then adjust the center of the new sizes' scrollbar. There might be easier ways, but this made the most sense to me.

JavaScript:
function zoom(type) {
    var container = document.getElementById('mapContainer');
    var zoomSlider = document.getElementById("zoom");
    var currentZoom = document.getElementById("currentZoom");
    var mapCur = document.getElementById("mapCur");
    if (type == "change") {
        var topPercent = (container.scrollTop + container.clientHeight/2) / container.scrollHeight;
        var leftPercent = (container.scrollLeft + container.clientWidth/2) / container.scrollWidth;
        mapCur.style.transform = "scale(" + (zoomSlider.value/100) + "," + (zoomSlider.value/100) + ")";
        var newTop = container.scrollHeight * topPercent - (container.clientHeight/2);
        var newLeft = container.scrollWidth * leftPercent - (container.clientWidth/2);
        container.scrollTo(newLeft, newTop);
        currentZoom.innerHTML = zoomSlider.value + "%";
    } else if (type == "reset") {
        zoomSlider.value = 100;
        currentZoom.innerHTML = zoomSlider.value + "%";
    }
}
 
Last edited:
Joined
Dec 14, 2021
Messages
28
Reaction score
2
Try changing your zoom function to the following. I think I've got the math figured out. I calculate the center of the current scrollbars, then adjust the center of the new sizes' scrollbar. There might be easier ways, but this made the most sense to me.
Thanks, it really helped.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,057
Messages
2,570,443
Members
47,113
Latest member
XZJMike318

Latest Threads

Top