Position div over particular region of variable height image
Asked Answered
P

4

9

I'm working to position a div over a variable height image and am wondering how best to approach this situation. In the following example, for instance, I'm trying to position the red square over the Registered trademark symbol in the image: Fiddle.

My HTML/CSS looks like this:

<img src="http://cisloandthomas.com/wp-content/uploads/2015/12/Shrunken-Banner-Wide-Ends-1140x200.jpg" class="background">
<div class="overlay"></div>

.background {
  height: 100%;
  position: absolute;
  margin-top: -61px;
}

.overlay {
  position: absolute;
  height: 20px;
  width: 20px;
  background: red;
}

And I'm positioning the red div over the image with the following JS:

var resizeOverlay = function() {
  var windowHeight = $(window).height();

  var left = windowHeight * 1.07;
  var bottom = (windowHeight * .63) + 61;

  $(".overlay").css({
    "left": left,
    "bottom": bottom
  });
};

$(document).ready(resizeOverlay);
$(window).resize(resizeOverlay);

The results are not ideal, because I'm just building two linear models to calculate the x and y offsets. How would others approach this task?

Paulino answered 8/6, 2016 at 13:13 Comment(4)
i would rather use photohopRaze
you have done a good job, it seems to be correct. When you change the height it changes image's dimensions but the square is of same shape. Hence they can't fit perfectly.Sucre
Thanks @NaeemShaikh, but if I burned the overlay into the image with Photoshop, I would still need a click listener over the region of the page that covers the red square, so the task would persist. Thanks as well Himanshu, but I'm wondering how one would approach the task in a non-arbitrary way (I was guessing and checking, but want to infer the formula mechanically).Paulino
@duhaime.. U must adjust the spot manually for each image.. No other optionsRaze
W
9

This can be achieved with CSS and a few changes to your markup

The image in your example is scaled in relation to the height of the viewport - the height is always 100% and the width is calculated on the fly by the browser to keep the aspect ratio.

To position the overlay the same scaling will need to apply. To do this a container can be added which will fit the viewport height and scale to the width of the image, this will then allow for the overlay to be positioned relatively to it and scale in proportion to the image.

The following modifications are required:

  • Wrap .background and .overlay in a container (called #container in this instance)
  • Set #container with the following properties:
    • height: 100vh; - This will make it fill the entire viewport height
    • margin-top: -61px; - Carried over from your example
    • position: relative; - To ensure that .overlay is positioned in relation to this container
    • width: 570vh; - This will ensure that the container scales at the same rate as the image. This is calculated by finding the aspect ratio of your existing image - 1140 x 200 is an aspect ratio of 57 : 10 so 200(px) * 5.7 = 1140(px) translates to 100(vh) * 5.7 = 570(vh)
  • Set .background with the following properties:
    • height: 100%; - To ensure it resizes in a similar manner to your example, it will fill the entire height of the viewport. The width will scale in relation to this
  • Set .overlay with the following properties:
    • background: red; - Carried over from your example
    • height: 6vh; - As the image is scaled in relation to the viewport height this will ensure that the overlay scales at the same rate
    • left: 18.3%; - Positions the overlay at the designated area over the registered symbol
    • position: absolute; - Positions the overlay relative to the container
    • top: 29%; - Positions the overlay at the designated area over the registered symbol
    • width: 6vh; - As the image is scaled in relation to the viewport height this will ensure that the overlay scales at the same rate

$(".overlay").click(function() {
  alert("Clicked")
});
#container {
  height: 100vh;
  margin-top: -61px;
  position: relative;
  width: 570vh;
}
.background {
  height: 100%;
}
.overlay {
  background: red;
  height: 6vh;
  left: 18.3%;
  position: absolute;
  top: 29%;
  width: 6vh;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <img alt="" class="background" src="http://cisloandthomas.com/wp-content/uploads/2015/12/Shrunken-Banner-Wide-Ends-1140x200.jpg">
  <div class="overlay"></div>
</div>

JS Fiddle - Change the result window height and the overlay should re-position accordingly.

Waterfront answered 13/9, 2016 at 12:5 Comment(0)
P
2

Walking home yesterday I realized this problem is actually very simple.

The image's proportions are constant, and the overlay has two values: x-position and y-position. The x-position is just some fraction of the image width, and the y-position is some fraction of the image height.

So one can represent the overlay's position using two float values {0,1}: one for the overlay's position on the x axis and the other for the y axis. Then just multiply those values by the image's width and height (respectively) to find the appropriate x,y positions for the overlay.

To get the overlay to stay constantly positioned over the point of interest (i.e. {0:max-image-x},{0:max-image-y} ) one just needs to subtract half the width of the overlay div from the x,y position calculated.

Paulino answered 13/9, 2016 at 21:29 Comment(0)
F
1

Here is fiddle , I realized after posting what is end of your question... Anyway I left answer here because at least it's precisely positioned. I think there is no better approach than one you tried already.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
    <style type="text/css">
        html, body, div, span, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, code,del, dfn, em, img, q, dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td{margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
        body{line-height:1.5;}
        table{border-collapse:separate;border-spacing:0;}caption, th, td{text-align:left;font-weight:normal;}
        table, td, th{vertical-align:middle;}
        blockquote:before, blockquote:after, q:before, q:after{content:"";}blockquote, q{quotes:"" "";}
        a img{border:none;}

        .background {
            height: 100%;
            position: absolute;
            margin-top: -61px;
        }

        .overlay {
            position: absolute;
            background: red;
            -moz-border-radius:100%;
            -webkit-border-radius:100%;
            border-radius:100%;
        }
    </style>
</head>
<body>
<script type="text/javascript">
    var resizeOverlay = function() {
        var l=515,
                t=145,
                $b=$('.background'),
                $o=$('.overlay'),
                o_w=25,
                o_h=25;
        var b_h=$b.height();
        var ratio=$b.width()/2800;
        $o.css({
            left:parseInt(l*ratio,10)+'px',
            top:parseInt(t*ratio-61,10)+'px',
            width:parseInt(o_w*ratio,10)+'px',
            height:parseInt(o_h*ratio,10)+'px'
        });
        console.log('background_height',b_h);
    };

    $(document).ready(resizeOverlay);
    $(window).resize(resizeOverlay);
</script>
<img src="http://cisloandthomas.com/wp-content/uploads/2015/12/Shrunken-Banner-Wide-Ends-1140x200.jpg" class="background">
<div class="overlay"></div>
</body>
</html>
Frida answered 12/9, 2016 at 22:7 Comment(0)
P
0

Years after the fact, I realized that an optimal way to position an element over a particular region of an image is to use an SVG, add the image to the SVG, and position SVG elements over the points of interest in the image.

This site has an example in which an image of a building has floors stacked on top of it so that hovering a floor (e.g. floor 22) highlights that floor:

enter image description here

Here's the relevant markup:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="4.5 0 980.9 545.9" x="0px" y="0px">
<g>
    <image height="546" overflow="visible" transform="matrix(0.9999 0 0 0.9999 4.4815 -0.9215)" width="981" href="https://www.360statestreet.com/wp-content/themes/statestreet360/images/floorplans/bg-floor_plans.jpg"/>
</g>
<g id="Floors">
    <polygon class="floor Floor7" fill="rgba(102,199,198,0.8)" id="Floor7" opacity="0" points="424,309 450,319 449,320 624,385 632,383 663,394 715,376 715,389 665,409 629,398 624,398 449,333 450,332 424,321" values="th"/>
    <polygon class="floor Floor8" fill="rgba(102,199,198,0.8)" id="Floor8" opacity="0" points="424,297 450,307 449,310 624,373 632,372 663,383 715,364 715,376 666,396 629,384 624,385 450,323 450,320 424,310" values="th"/>
    <polygon class="floor Floor9" fill="rgba(102,199,198,0.8)" id="Floor9" opacity="0" points="424,287 450,297 450,299 625,361 633,360 665,371 715,352 715,365 667,382 630,372 624,374 450,311 450,308 424,299" values="th"/>
    <polygon class="floor Floor10" fill="rgba(102,199,198,0.8)" id="Floor10" opacity="0" points="424,275 450,284 450,287 627,349 634,345 668,358 715,340 715,353 668,372 630,359 628,361 450,300 450,296 424,287" values="th"/>
    <polygon class="floor Floor11" fill="rgba(102,199,198,0.8)" id="Floor11" opacity="0" points="424,263 450,271 450,275 627,337 634,334 667,345 715,327 715,340 667,358 635,346 627,349 450,287 450,284 424,275" values="th"/>
    <polygon class="floor Floor12" fill="rgba(102,199,198,0.8)" id="Floor12" opacity="0" points="424,252 450,261 450,264 627,324 635,322 667,332 715,315 715,327 668,346 635,334 627,337 450,276 450,274 424,265" values="th"/>
    <polygon class="floor Floor13" fill="rgba(102,199,198,0.8)" id="Floor13" opacity="0" points="424,240 451,249 451,251 628,310 635,308 668,319 715,301 715,315 668,333 635,322 628,325 450,265 450,263 424,254" values="th"/>
    <polygon class="floor Floor14" fill="rgba(102,199,198,0.8)" id="Floor14" opacity="0" points="424,228 451,237 451,240 628,297 635,296 668,307 715,289 715,302 668,320 634,309 628,310 450,252 450,250 424,241" values="th"/>
    <polygon class="floor Floor15" fill="rgba(102,199,198,0.8)" id="Floor15" opacity="0" points="424,216 451,225 451,227 628,284 634,284 668,295 715,277 715,290 670,307 634,295 628,298 450,240 450,238 424,229" values="th"/>
    <polygon class="floor Floor16" fill="rgba(102,199,198,0.8)" id="Floor16" opacity="0" points="424,203 451,213 451,216 628,272 634,271 668,282 715,265 715,277 669,295 634,284 628,286 450,228 450,225 424,216" values="th"/>
    <polygon class="floor Floor17" fill="rgba(102,199,198,0.8)" id="Floor17" opacity="0" points="424,192 451,203 451,205 628,260 634,259 668,270 715,253 715,265 669,282 634,271 628,273 450,216 450,213 424,204" values="th"/>
    <polygon class="floor Floor18" fill="rgba(102,199,198,0.8)" id="Floor18" opacity="0" points="424,182 451,191 451,193 629,248 634,246 668,257 715,240 715,253 669,270 634,258 628,261 450,205 450,202 424,194" values="th"/>
    <polygon class="floor Floor19" fill="rgba(102,199,198,0.8)" id="Floor19" opacity="0" points="424,171 451,179 451,181 629,235 630,233 668,245 715,228 715,240 669,257 634,246 628,249 450,193 450,190 424,183" values="th"/>
    <polygon class="floor Floor20" fill="rgba(102,199,198,0.8)" id="Floor20" opacity="0" points="424,160 451,167 451,170 629,224 632,222 668,232 715,215 715,228 669,245 634,234 628,237 450,182 450,179 424,171" values="th"/>
    <polygon class="floor Floor21" fill="rgba(102,199,198,0.8)" id="Floor21" opacity="0" points="424,148 450,156 451,160 629,212 633,209 668,220 715,204 715,216 669,233 634,222 628,225 450,172 450,168 424,160" values="st"/>
    <polygon class="floor Floor22" fill="rgba(102,199,198,0.8)" id="Floor22" opacity="0" points="424,138 450,144 451,147 629,200 633,198 668,207 715,191 715,205 669,221 634,212 628,214 450,162 450,158 424,150" values="nd"/>
    <polygon class="floor Floor23" fill="rgba(102,199,198,0.8)" id="Floor23" opacity="0" points="424,126 452,135 451,136 629,187 633,185 668,195 715,181 715,194 669,211 634,200 628,202 450,149 450,147 424,139" values="rd"/>
    <polygon class="floor Floor24" fill="rgba(102,199,198,0.8)" id="Floor24" opacity="0" points="424,116 452,124 451,125 629,176 633,173 668,183 715,166 715,180 669,195 634,187 628,189 450,137 450,135 424,129" values="th"/>
    <polygon class="floor Floor25" fill="rgba(102,199,198,0.8)" id="Floor25" opacity="0" points="424,103 452,111 451,113 629,162 633,160 668,170 715,155 715,168 669,183 634,173 628,176 450,127 450,125 424,117" values="th"/>
    <polygon class="floor Floor26" fill="rgba(102,199,198,0.8)" id="Floor26" opacity="0" points="424,91 452,99 451,101 629,150 633,148 668,157 715,142 715,156 669,171 634,161 628,164 450,115 450,112 424,105" values="th"/>
    <polygon class="floor Floor27" fill="rgba(102,199,198,0.8)" id="Floor27" opacity="0" points="424,80 452,88 451,90 629,138 634,135 668,144 715,130 715,143 669,158 634,149 628,151 450,103 450,100 424,93" values="th"/>
    <polygon class="floor Floor28" fill="rgba(102,199,198,0.8)" id="Floor28" opacity="0" points="425,69 452,76 451,78 629,126 634,123 668,132 715,118 715,131 669,145 634,136 628,139 450,91 450,88 424,81" values="th"/>
    <polygon class="floor Floor29" fill="rgba(102,199,198,0.8)" id="Floor29" opacity="0" points="449,59 449,63 448,65 513,81 525,78 557,86 557,92 622,108 632,109 681,95 681,94 681,104 715,112 664,128 630,120 622,121 449,76 446,72 426,66" values="th"/>
    <polygon class="floor Floor30" fill="rgba(102,199,198,0.8)" id="Floor30" opacity="0" points="451,54 513,70 527,67 556,73 557,79 623,95 681,81 680,95 632,109 622,109 556,93 555,85 526,79 513,82 451,66" values="th"/>
    <polygon class="floor Floor31" fill="rgba(102,199,198,0.8)" id="Floor31" opacity="0" points="451,40 513,55 527,52 556,59 557,65 623,81 680,68 681,81 632,94 622,96 556,79 555,73 526,67 513,70 451,53" values="st"/>
</g>
</svg>

The building image is stored in the image tag, and each floor gets a polygon positioned over the image. SVG resize rules handle the SVG sizing, and all children elements scale with the rescaled image!

Paulino answered 17/2, 2018 at 13:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.