Trying to align image and canvas - image

First-time posting a question, and I avow up front that my HTML/CSS/Javascript knowledge is ... shall we say scrappy. I usually manage, but I can't seem to figure this out.
All I want to do is display an image centered. Then create a canvas, position the canvas over the image, and draw on it. Then have the canvas stay with the image as the browser is re-sized. Here's what I have so far (I confess, I got much of the Javascript code from another poster, and I'm trying to use it as a learning example):
<!DOCTYPE html>
<html>
<head>
<script>
function myInit()
{
hdc = set_canvas();
hdc.fillRect(0, 0, 50, 50);
}
function set_canvas()
{
var img = document.getElementById('audubon_image');
var x = img.offsetLeft,
y = img.offsetTop,
w = img.clientWidth,
h = img.clientHeight;
var c = document.getElementById('myCanvas');
img.parentNode.appendChild(c);
c.style.zIndex = 1;
c.style.left = x + 'px';
c.style.top = y + 'px';
c.setAttribute('width', w+'px');
c.setAttribute('height', h+'px');
hdc = c.getContext('2d');
return(hdc);
}
</script>
<style>
#container
{
text-align: center;
}
canvas
{
pointer-events: none;
position: absolute;
border: 1px solid black;
}
</style>
</head>
<body onload='myInit()'>
<div id="container">
<img src="http://www.sturtz.org/john/audubon/wp-content/uploads/2015/04/Audubon.jpg" id="audubon_image" />
<canvas id='myCanvas'></canvas> <!-- gets re-positioned in myInit(); -->
</div>
</body>
</html>
What's supposed to happen: The image gets placed. Then the Javascript code determines the position and size of the image, and sets the canvas to match. Then draws on the canvas (for the moment, a lovely elegant block box in the upper left corner).
So far, so good. But since the image centered, if the browser is re-sized (specifically made wider or narrower), the image's position moves relative to the left and right edges of the browser window.
With 'position: absolute' specified for the canvas, the canvas does not move (unsurprisingly; I suppose that's what absolute means). So the image and canvas do not stay aligned.
If I change the canvas CSS to 'position: relative', then when I re-size the window, the image and canvas remain in the same position relative to one another (which is what I want). But then I can't get the canvas over the top of the image.
My gut feel is that this should be possible (easy, even), and my lack of knowledge is causing me not to see it.

I think I'm on to it.
Put the canvas in a div. Wrap that and the img in a container div. Specify 'position: relative' for the outer div, 'position: absolute' for the inner div. That way, the x and y coordinates of the div containing the canvas may simply be specified as (0,0).
<!DOCTYPE html>
<html>
<head>
<script>
function myInit()
{
hdc = set_canvas();
hdc.fillRect(0, 0, 50, 50);
}
function set_canvas()
{
var c = document.getElementById('map_canvas');
c.style.zIndex = 1;
c.setAttribute('width', '650px');
c.setAttribute('height', '300px');
hdc = c.getContext('2d');
return(hdc);
}
</script>
<style>
#image_container
{
margin-left: auto;
margin-right: auto;
width: 650px;
position: relative;
}
#canvas_container
{
position: absolute;
top: 0px;
left: 0px;
}
#map_canvas
{
}
</style>
</head>
<body onload='myInit()'>
<div id="image_container">
<img src="http://www.sturtz.org/john/audubon/wp-content/uploads/2015/04/Audubon.jpg" id="audubon_image" />
<div id="canvas_container">
<canvas id="map_canvas"></canvas>
</div>
</div>
</body>
</html>

How to position the canvas directly over the img with the container horizontally centered.
Keep the canvas directly over the image
Set both #audubon_image and #myCanvas to position:absolute inside the #container that's set to position:relative.
Center the container div
margin:0 auto; to center #container on the page.
CSS
#container{
margin:0 auto;
position:relative;
border:1px solid blue;
}
#audubon_image,#myCanvas{position:absolute; top:0px; left:0px;}
#audubon_image{border:1px solid green;}
#myCanvas{ border:1px solid red;}
Javascript
Set the #container's CSS size and #canvas's element size to equal the img's size. Be sure to set the canvas element size (not css size) or your canvas drawings will be distorted.
// get a reference to #audubon_image
var img=document.getElementById('audubon_image');
// set #container's size to equal the #audubon_image size
var container=document.getElementById('container');
container.style.width=img.width+'px';
container.style.height=img.height+'px';
// set #myCanvas's size to equal the #audubon_image size
var canvas=document.getElementById('myCanvas');
canvas.width=img.width;
canvas.height=img.height;
Note: Once in a great while, browsers will fire window.onload before the image's width & height are set (shame on you browsers!). So in production, you might "defensively" wrap the javascript inside a setTimeout of 1 second to be sure the image's width & height have been set.
Full code and a Demo:
window.onload = (function() {
// get a reference to #audubon_image
var img = document.getElementById('audubon_image');
// set #container's size to equal the #audubon_image size
var container = document.getElementById('container');
container.style.width = img.width + 'px';
container.style.height = img.height + 'px';
// set #myCanvas's size to equal the #audubon_image size
var canvas = document.getElementById('myCanvas');
canvas.width = img.width;
canvas.height = img.height;
});
body {
background-color: ivory;
}
#container {
margin: 0 auto;
position: relative;
border: 1px solid blue;
}
#audubon_image,
#myCanvas {
position: absolute;
top: 0px;
left: 0px;
}
#audubon_image {
border: 1px solid green;
}
#myCanvas {
border: 1px solid red;
}
<div id="container">
<img id="audubon_image" src='https://dl.dropboxusercontent.com/u/139992952/multple/character3.png' />
<canvas id='myCanvas'></canvas>
</div>

Related

Intersection Observer with viewport margins in Alpine

Problem:
Need to execute an action when an element enters the middle third area of the viewport:
Constraints:
I am using Alpine JS.
According to the Alpine intersect docs, I can control the rootMargin property of the underlying IntersectionObserver using .margin, in order to change the limit where the observer will trigger. I'm doing it as follows:
h1 {
margin-top: 95vh;
position: relative;
background-color: blue;
color: white;
z-index: 2;
}
body {
height: 200vh;
}
body::before,
body::after {
content: '';
position: fixed;
left: 0;
right: 0;
height: 33%;
background-color: grey;
z-index: 1;
}
body::before{
top: 0;
}
body::after{
bottom: 0;
}
<html>
<head>
<!-- Alpine Plugins -->
<script defer src="https://unpkg.com/#alpinejs/intersect#3.x.x/dist/cdn.min.js"></script>
<!-- Alpine Core -->
<script defer src="https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js"></script>
</head>
<body>
<h1 x-data="{ message: 'Alpine Is Working' }"
x-intersect:enter.margin.-33%.0.-33%.0="message = 'ENTERED'"
x-intersect:leave.margin.-33%.0.-33%.0="message = 'LEFT'"
x-text="message"></h1>
</body>
</html>
In the above example, you can see it's not respecting the 33% top/bottom margin with the viewport. I marked those in grey using pseudoelements.
What should happen:
In the example above, it should say "Entered" or "Left" when the element scrolls into and out of the white area.
Any idea on what I may be doing wrong?
Thanks!
Your code wouldn't work for me in the code snippet, but did as soon as I copied it out to a local html file and ran it there.
The iframe is messing with the intersection observer's root.
Your code is useful to me, I hadn't been able to find an example combining the :enter and :leave modifiers.

How to make rotated <hr> line length adapt to page height?

I have a rotated hr line. See far right here.
Is it possible to make the line's length adapt to the height of the page?
Thank you!
Here is a script that calculates letter-spacing:
#container {
width: 50px;
height: 500px;
display: block;
border: 1px solid red;
}
p {
writing-mode: vertical-rl;
text-orientation: mixed;
}
<div id="container">
<p>My Text Here</p>
<script>
const container = document.querySelector('#container');
const text = container.querySelector('p');
const height0 = text.offsetHeight;
text.style.letterSpacing = '1px';
const height1 = text.offsetHeight;
const spacing = (container.offsetHeight - height0 - 2) / (height1 - height0);
text.style.letterSpacing = `${spacing}px`;
</script>
</div>
Tried also text-align: justify with text-justify and it seems to be incompatible with vertically oriented texts...

Pdf.js basic guide/tutorial to build a viewer with zoom pan and scroll

I am trying to build from scratch a minimalist Pdf.js viewer: I would just need zoom, pan and actual page number/overall pages number.
I am able to set the initial zoom so that the pdf is shown as I want at the beginning, i.e. it fits one of the two dimension of the available screen (for clarity in my code below I directly set the height property supposing the aspect ratio (height / width) of the document is higher than that of the available screen). Here is my code:
<!DOCTYPE html>
<html style="margin: 0; padding: 0; border: 0;
height:100%; width:100%">
<head>
<title>PDF.js Learning</title>
</head>
<body style="background-color:rgba(0, 0, 0, 0.78); margin: 0; padding: 0;
border: 0; height:100%; width:100%">
<div style="position: relative; margin: 0; padding: 0; border: 0;
height:100%; width:100%">
<canvas id="the-canvas" style="position: absolute; margin: 0;
padding: 0; border: 0; top: 50%;
left: 50%;
transform: translate(-50%, -50%);">
</canvas>
</div>
<!-- JQuery libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<!-- Pdf.js libraries -->
<script type="text/javascript" src="build\pdf.js"></script>
<script type="text/javascript" src="web\compatibility.js></script>
<script>
var url = "your_PDF_url";
// Asynchronous download PDF
function openPdf () {
PDFJS.getDocument(url).then(function(pdf) {
return pdf.getPage(1);
}).then(function(page) {
/* Get viewport (dimensions) and setting scale depending on
the relative aspect ratio of the pdf and window*/
var desiredHeight = $(window).height(); //or width
var viewport = page.getViewport(1);
var scale = desiredHeight / viewport.height; //or width
viewport = page.getViewport(scale);
// Get canvas#the-canvas
var canvas = document.getElementById('the-canvas');
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
canvas.height = viewport.height;
canvas.width = viewport.width;
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport
};
// Render PDF page
page.render(renderContext);
});
}
$(document).ready(function() {
(openPdf());
});
$(window).resize(function() {
(openPdf());
});
</script>
</body>
</html>
I can't find anywhere how I should do if I want to resize the pdf document or if I want to zoom it in and out:
should I reload the document and re-render? Should I only re-render it (as, if I haven't misunderstood, the pdf file once loaded, should be already available) with a new scale? Is there a less computation option than the 2 above?
I tried the first one (calling the PDFJS.getDocument() on resize) but it is really consuming and sometimes I get a bad rendering or no render at all.
Is there a reference for this and for pan somewhere? And how to show scroll bar, in the case of multiple pages documents, to change page? Thank you for your help.

HTML: white space around elements, how to remove?

My webpage contains several divs. Some are set to width: 100%, so they fill the whole page width.
But at the top of the page there is a small whitespace before the first element shows up. Moreover, that same whitespace is visible left and right from elements spanning the whole page width.
I cannot figure out why. If I set:
html, body {
width: 100%;
}
then the whitespace remains but the page is just stretched out to fit the image width of a div.
Can anyone help? It's probably pretty simple but I must be overlooking something.
Thank you.
EDIT: I must mention I'm using a parallax element. This uses a padding, so the image does fills the whole div and does not leave a black area on top. The HTML is:
<div class="js-background-1 container">
</div>
The CSS:
.container {
padding-top: 200px;
}
.js-background-1 {
background: transparent url(url/to/image) center 0 no-repeat;
}
And the javascript:
<script type="text/javascript">
var $window = $(window);
var velocity = 0.4;
function update(){
var pos = $window.scrollTop();
$('.container').each(function() {
var $element = $(this);
var height = $element.height();
$(this).css('backgroundPosition', '50% ' + Math.round((height - pos) * velocity) + 'px');
});
};
$window.bind('scroll', update);
</script>
I used the tutorial from http://www.webdesign.org/how-to-create-a-parallax-scrolling-website.22336.html, so there is where it is from. I changed the HTML a bit for my website, but the rest is the same.
I saw the comment about the margin and padding set to 0, but that leads to my div to have a blank space if you don't scroll far enough.
You must remove the margin on body:
body {
padding:0;
margin:0;
}
You can also remove padding and margin on html and body
html, body {
padding:0;
margin:0;
}
See it on jsfiddle
But I would not advise to use * (the universal selector)
* {
margin: 0px;
padding: 0px;
}
This would remove padding and margins on all elements.
The good method is to always use at the begining of the file (I forgot to metion this):
*{
margin: 0px;
padding: 0px;
}
This two line's at the begining of main CSS file fix many problem's that you can encounter.
Hope it'll help you.
padding-bottom: 20px;
border: 1px solid red !important;
margin: 0;
padding: 0;
width: 100%;

IE8 non-compatibility mode, image with max-width and height:auto

I have an image with this markup
<img src="wedding_00.jpg" width="900" height="600" />
And I am using CSS to downsize it to 600px width, like so:
img {
max-width:600px;
height:auto;
}
Can anyone explain why this method works in Compatibility mode, but not in standard mode? Is there a way I can modify my CSS so that it will work in standard mode?
I realize that if I strip out the
width="900" height="600"
that it solves the problem, but that is not an option I have.
I'm not sure of the root cause but if you add
width: auto;
then it works.
set width:inherit for ie8
img {
width:inherit; //for ie8
max-width: 100%;
height: auto;
}
Wow, saved me a lot of time there!
i had a similar problem with an image in position: absolute where width was magically taking max-width value. Its weird because it doesn't do that when the image wasn't in position: absolute.
width: auto;
max-width: 200px;
height: auto;
max-height: 200px;
works great in IE8!
Wow, what a pain IE always seems to be. Although there is an accepted answer, I found that it did not solve my problem.
After much search I found that the way to fix it is to remove the height and width attributes from the images in question. An explanation can be found here: Scaling Images in IE8 with CSS max-width
The code is as follows:
CSS:
.entry img {
max-width:615px
height:auto;
}
SCRIPT
var imgs, i, w;
var imgs = document.getElementsByTagName( 'img' );
for( i = 0; i < imgs.length; i++ ) {
w = imgs[i].getAttribute( 'width' );
if ( 615 < w ) {
imgs[i].removeAttribute( 'width' );
imgs[i].removeAttribute( 'height' );
}
}
Now I tend to use jQuery as much as possible, to solve this I used a few different functions to target IE8 and make my life easier. I also found that the solution almost worked, but not quite. I toyed around with it until I was able to achieve the results I was looking for. My solution is as follows:
JQUERY:
var maxWidth = 500;
function badBrowser(){
if($.browser.msie && parseInt($.browser.version) <= 8){
return true;
}
return false;
}
if(badBrowser()){
$('img').each(function(){
var height = $(this).height();
var width = $(this).width();
if (width > maxWidth) {
var ratio = (maxWidth /width)
$(this).css({
"width":maxWidth,
"height":(ratio*height)
});
$(this).removeAttr('width');
$(this).removeAttr('height');
}else{
$("#cropimage").css({
"width":width,
"height":height
});
}
});
}
I use this to target a specific image load function, but it could be added to any document ready or window load function as well.
My solution for this issue was:
<!--[if IE 8]>
<style>
a.link img{
max-height:500px ;
width:auto !important;
max-width:400px;
height:auto !important;
width:1px;
}
</style>
<![endif]-->
max-width of images just work fine on IE8 when it's directly wrapper (div) has width.
Example:
The image in this example is 700px;
The web's width is 900px;
<div class="wrapper1"><div class="wrapper2"><img style="max-width: 100%;" src="abc.jpg" alt="Abc" /></div></div>
if you style:
.wrapper1 { width: 50%; float: left; } // this column's width is 450px max;
The image still 700px and make the layout broken.
Solution:
.wrapper1 { width: 50%; float: left; } // this column's width is 450px max;
.wrapper2 { width 100%; float: left; } // if it has border or padding, width will smaller 100%
The the image will fit the column (image = 450px) when resize window smaller, image will smaller based on wrapper2's width.
Regards,
Cuong Sky

Resources