can't stop createImg element resizing viewport when part off the canvas

Hi, I'm having trouble stopping an image element increasing the size of the viewport when it sits partway off of the canvas.

I have tried adapting a solution suggested here http://stackoverflow.com/questions/6746649/css-hide-element-off-the-right-of-the-screen involving placing an element within another element which has styling set to overflow:hidden and position:relative to no avail –the image just disappears.

Although commenting/uncommenting the pictureContainer.style("position", "relative"); in the code below does actually hide/show the image, which makes me wonder if it's some kind of conflict between p5js and html styling?!

I have alternatively tried setting up the parent container in the index.html and doing var x = select"(parent div #id in index.html"); picture.parent(x); in my sketch script but I get the same result as above.

FYI, I am using createImg from p5.dom.js and then using .style to position the image etc. as the project is running in a phonegap shell and I have had issues with loadImage on iOS.

Any help is hugely appreciated... especially as it's part of an app that's going to be used by NHS staff in a few weeks time :/

Here's my problem code:

//time keeping
var timeKeeper;

//picture container
var pictureContainer;
//picture
var pictureLoaded;
var picture;

//display picture bool
var pictureDisplay;

//p5 canvas
var canvas;

function setup() {

  //create the p5 canvas element
  canvas = createCanvas(windowWidth, windowHeight);

  // canvas.style("zIndex", "-1") //changing this doesn't seem to help

  //container to hold picture and supposedly prevent it affecting the viewport
  pictureContainer = createDiv("test");
  pictureContainer.style("overflow", "hidden");
  pictureContainer.style("position", "relative");
  // pictureContainer.position(0,0); //this doesn't do anything differently to the line above except move the container to top left of window
  pictureContainer.style("width", "0");
  pictureContainer.style("zIndex", "999");

  //create image
  picture = createImg("http://images.clipartpanda.com/foam-clipart-1334260620683400173foam_finger.svg", "fingerTransparent")
  //make picture the child of pictureContainer
  picture.parent(pictureContainer);

  //position(x,y) sets the image position styling to position:absolute, left:x, top:y -- as such:http://p5js.org/reference/#/p5.Element/position
  picture.position(windowWidth/2,windowHeight/2); 
  //for displaying/hiding the picture  
  pictureDisplay = false;
  timeKeeper = 0;

}


function draw() {


  canvas.background(100, 100, 100);

  //display/show picture
  if(millis()>timeKeeper+1000){
    timeKeeper=millis();
    if(pictureDisplay){
      picture.style("display","initial"); 
      pictureDisplay=false;
    }
    else{
      picture.style("display","none"); 
      pictureDisplay=true;
    }
  }

}

Answers

  • This is just a HTML/CSS issue. Are you already familiar with your browser's inspector tool? You can use that to see (and test/edit) the styling being applied to elements on the page. In this case you have at least two significant problems:

    1. wrapper element has width 0 and no height set: What do you expect to see when you set the div width to 0?
    2. the image is positioned at windowWidth/2,windowHeight/2 where windowWidth is the width of your browser window. You'll need to set the width of your wrapper to windowWidth; otherwise you're positioning the image outside the wrapper where it will be invisible...

    Also, watching people try and use p5's DOM library like this is really painful. Instead of applying styling - one property at a time - in your script; just use addClass and do your styling in a separate CSS file!

  • edited May 2016

    Hi, thanks for your answer, it helped me figure out where I was going.

    Ok, so playing with width by itself doesn't fix it, neither removing it nor changing it to windowWidth (which anyway I don't think can be done dynamically without a PHP script to pass the windowWidth variable into the CSS)... And Re: your point 2, what I'm after is actually for the part of image that is not in the window to be invisible. Anyhow, width does need to be removed for the following...

    The fix is in the parent/child hierarchy. Very simply all that needed done was for the canvas element to also be made the child of the container div.

    Though the sloppy use of p5.dom.js you rightly point out was only a product of trying to get something up on the forum quickly, I have taken your suggestions about using classes for CSS :)

    Here's the working code:

    ===./css/overflowContainer.css===

    .container {
        overflow: hidden;
        position: relative;
    }
    

    ===./index.html===

    <!DOCTYPE html>
    
    
    <html>
    
    
        <head>
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    
            <script type="text/javascript" language="javascript" src="js/p5.js"></script>
    
            <script type="text/javascript" language="javascript" src="js/p5.dom.js"></script>        
    
            <script language="javascript" type="text/javascript" src="p5sketch.js" ></script>
    
            <link rel="stylesheet" type="text/css" href="css/overflowContainer.css">
    
            <style> body {padding: 0; margin: 0;} </style>
    
        </head>
    
        <body>
    
        </body>
    </html>
    

    ===./p5sketch.js===

    //time keeping
    var timeKeeper;
    
    //picture container
    var pictureContainer;
    //picture
    var pictureLoaded;
    var picture;
    
    //display picture bool
    var pictureDisplay;
    
    //p5 canvas
    var canvas;
    
    function setup() {
    
      //create the p5 canvas element
      canvas = createCanvas(windowWidth,windowHeight);
      //create image
      picture = createImg("http://images.clipartpanda.com/foam-clipart-1334260620683400173foam_finger.svg", "fingerTransparent")
    
      //container to hold elements and prevent them resizing the viewport
      elementContainer = createDiv("");
      elementContainer.addClass("container");
      // //make the elementContainer the parent of canvas and picture
      canvas.parent(elementContainer);
      picture.parent(elementContainer);
    
    
      //size and position the picture
      picture.size(windowWidth, windowHeight);
      picture.position(windowWidth/2,windowHeight/2); 
    
      //for displaying/hiding the picture  
      pictureDisplay = false;
      timeKeeper = 0;
    
    }
    
    function draw() {
      background(100, 100, 100);
    
      //display/show picture
      if(millis()>timeKeeper+1000){
        timeKeeper=millis();
        if(pictureDisplay){
          picture.style("display","initial"); 
          pictureDisplay=false;
        }
        else{
          picture.style("display","none"); 
          pictureDisplay=true;
        }
      }
    
    }
    
  • edited May 2016

    The fix is in the parent/child hierarchy. Very simply all that needed done was for the canvas element to also be made the child of the container div.

    There's more to it than that. The width and height of your container needed to be set in order to apply the solution you had linked to. By moving the canvas element inside the container div you have set the width/height of that container to the width/height of the canvas - which just happens to be windowWidth/Height. You could achieve the same effect by setting the width/height of the container via the script - and that's actually a legitimate use of the style() method - PHP into CSS?!? yuck... :(|)

    However what you also achieve by moving canvas into the same container is to ensure the image is positioned relative to the canvas element - and that is something I'd overlooked earlier as I didn't have time to properly figure out what you were trying to achieve. With the canvas outside the container the container is positioned after the canvas in the flow of the document with the image then positioned relative to this new position: so not where you wanted it...

    Assuming you're doing a single page app with no scrolling it's actually simpler to do away with the container altogether and simply set overflow: hidden on the body tag:

    var picture;
    var canvas;
    
    function setup() {
      canvas = createCanvas(windowWidth,windowHeight);
    
      picture = createImg("http://" + "images.clipartpanda.com/foam-clipart-1334260620683400173foam_finger.svg", "fingerTransparent")
    
      // plain JS makes setting multiple style attributes
      // much simpler...
      document.getElementsByTagName('body')[0].setAttribute("style", "margin:0; overflow: hidden;")
    
      picture.size(windowWidth, windowHeight); 
      // notice that p5 achieves this by setting position absolute
      // on the image
      picture.position(windowWidth/2,windowHeight/2); 
    
    }
    
    function draw() {
      background(100);
    
    }
    
  • Hey, Thanks again! Especially for taking the time to give a full explanation.

    As may be obvious I'm pretty new to html/css/js coding and so probably being a bit sloppy in places.

    And yes, I ran a mile at the idea of delivering variables into CSS via PHP, just that someone on stackexchange had suggested it and I couldn't find a way of passing variables to CSS from within a p5 sketch...

    ...you suggested that it would be possible to set the container dimensions via the script and in your initial answer that one could set the height/width of the div container to windowWidth. I see dimensions of a div can be set using container.style("width", "somewidthpx") but I cannot see how I could actually pass a p5 variable e.g. windowWidth or something else I had declared to the 2nd argument (width value) as it is expecting a string.

    I played around for a moment with toString() but that didn't work as the arguments in the style.() method are held in quotation marks anyway. I'm probably confusing matters massively here but would like to find a way to dynamically set style properties according to variables from within my p5 sketch. Any ideas? What am I missing?

    Cheers!

  • I cannot see how I could actually pass a p5 variable e.g. windowWidth or something else I had declared to the 2nd argument (width value) as it is expecting a string

    That's an example of a really odd design decision in p5: something that would be trivial in raw JS becomes more fiddly in something that's meant to be making your life easier... :/

    Try: container.style("width", String(ANumericVariable)); though TBH having to do it that way makes me squirm in discomfort :(

  • Cool, so how else would you do it? i.e. your initial suggestion to set container width to the p5 variable windowWidth?

  • Just double-checked: according to the reference style() should accept a number as a parameter; but passing one throws an error so this actually looks like a bug.

    My suggested workaround does work - which looking at the docs seems odd to me as I would expect the string to require a measurement unit (like "px"). And in fact you can coerce the number variable to a string easily enough by adding "px" as in the following example:

    function setup() {
      createCanvas(100,20);
    
      var foo = createDiv("foo");
      foo.style("background", "#f90");
      foo.style("width", String(windowWidth)); // surprised this works
      foo.style("height", windowHeight + "px");
    }
    
  • Cool, so how else would you do it? i.e. your initial suggestion to set container width to the p5 variable

    Didn't see this before sending my previous answer...

    @-) #-o 8-} :))

    Oops - the simplest solution would actually be to use a different method:

    function setup() {
      createCanvas(100,20);
    
      var foo = createDiv("foo");
      foo.style("background", "#f90");
      foo.size(windowWidth, windowHeight); 
    }  
    
  • edited May 2016

    Cheers for persevering.

    Yeah style() seems fine just passing a number for CSS parameters which only require a number anyway, e.g. opacity accepts a float just fine.

    However it was the ones requiring a measurement unit, e.g. pxas you say, which I was having trouble with. I had tried passing string variables to the parentheses - eg. var x = 50px ... .style("width", x) - but that didn't work (as I guess it's not intended to reference a variable like that), and I stopped short of doing concatenation inside of the parentheses itself... Which you have shown to work :)

    Weird that .size() accepts the special windowWidth/Height variables tho... Must be because they're system variables?!

    Very useful, thanks!

Sign In or Register to comment.