placing slider relative to canvas in instance mode

I'm trying to place a slider in a p5 sketch running in instance mode. However, the slider position is calculated relative to the html page, and not relative to the origin of the canvas. So for example if the canvas is in a different location, the slider won't move with it.

How can I place the slider relative to the canvas? (i.e. in a manner similar to other p5 objects, like images, etc.)

Here's my test code:

var testslider = function(p){

    var slider;

    p.setup = function() {
      p.createCanvas(400, 400);
      p.background(200);
      slider = p.createSlider(0, 255, 100);
      slider.position(0, 20);
    }

    p.draw = function() {
    }

}

Thanks!

Answers

  • Answer ✓

    Set a target div to push your canvas into and make sure this has position: relative applied:

    HTML:

    <body>
        <div id="myTargetDiv" style="position: relative;"></div>
    </body>
    

    I've added the CSS inline for expediency; but better to do this in a separate CSS file ;)

    // instantiate p5 with target

    new p5(testslider, "myTargetDiv");

    Since the slider also gets added inside the container div both it and the canvas are positioned relative to the container.

  • edited June 2016

    Thanks, this is very helpful. I'm still running into an issue though. Previously I was centering my canvas as follows (in the HTML):

    <body>    
         <div id="myTargetDiv" align="center"></div>
    </body>
    

    if I add the CSS you suggest, then it only works correctly if I remove the center alignment. I.e. this doesn't work:

    <body>
         <div id="myTargetDiv" style="position: relative;" align="center"></div>
    </body>
    

    Is there a way I can position the slider relative to the canvas while also centering the div in which they are contained?

  • edited April 2019 Answer ✓

    I've made my own research and I think I've found out some way to pull that out. <:-P
    Seems like the canvas' offsets are its x & y properties. >-)
    So we take that for consideration when using position() for the rest of the p5.Element objects. *-:)

    Go to following link and see it in action online:
    http://CodePen.io/GoSubRoutine/pen/KNbwLW?editors=1010

    Or save the sketch below as an ".html" file and run it under some Firefox-based browser: :D

    <script src=http://p5js.org/assets/js/p5.min.js></script>
    <script src=http://p5js.org/assets/js/p5.dom.min.js></script>
    
    <script>
    
    /**
     * Element Relative to Canvas (v1.3)
     * GoToLoop (2016-Jun-09)
     *
     * https://Forum.Processing.org/two/discussion/17074/
     * placing-slider-relative-to-canvas-in-instance-mode#Item_3
     *
     * http://CodePen.io/GoSubRoutine/pen/KNbwLW?editors=101
    */
    
    "use strict";
    
    new p5(p => {
      let slider;
    
      p.setup = () => {
        p.createCanvas(600, 400);
        slider = p.createSlider(0, 0xff, 0x80).size(p.width>>1, p.AUTO);
        p.windowResized();
      };
    
      p.draw = () => {
        p.background(slider.value());
      };
    
      p.windowResized = () => {
        p._renderer.position(p.windowWidth  - p.width  >> 1,
                             p.windowHeight - p.height >> 1);
    
        const sliderX = (p.width  - slider.width  >> 1) + p._renderer.x,
              sliderY = (p.height - slider.height >> 1) + p._curElement.y;
    
        slider.position(sliderX, sliderY);
      };
    });
    
    </script>
    
  • edited June 2016

    Thanks for all your help! I ended up using a similar solution of adding the canvas position to the scrollbar position

    var testslider = function(p){
    
        var slider, c;
    
        p.setup = function() {
          c = p.createCanvas(400, 400);
          p.background(200);
          slider = p.createSlider(0, 200, 100);
          c.position();
          slider.position(c.position().x,c.position().y);
          slider.position(c.position().x,c.position().y);
        }
    
        p.draw = function() {
        }
    
        p.windowResized = function(){
            slider.position(c.position().x,c.position().y);
        }
    }
    

    This works without having to add position:relative to CSS.

    HTML:

    <body>
       <div id="testslider" align="center"></div>
    </body>
    

    One quirk I noticed is that the first time slider.position is called, it was incorrectly placed, but the second time it was correctly placed. Don't understand why, that's possibly a bug.

  • Updated to v1.2. It's using windowResized() now as well. :\">

  • @aatish @GoToLoop

    The slider and sketch canvas are DOM elements and so it is more appropriate (i.e. best practice) to position them relative to each other using CSS techniques that are standard practice in the web design/development community. p5's position() method simply adds an inline style - i.e. CSS - so there's no point hacking around in your sketch to address an 'issue' that can be fixed with a line of CSS (you can put position: relative on body if you want). Doing so simply adds complexity to your code; is frankly insane; and leaves me weeping tears of pain :(( :(( :((

  • @aatish sorry: just noticed your supplementary question. Adding align to a div is deprecated in HTML5. You should be centering your div with CSS. IIRC you may have to set the wrapper div width to match the canvas and then centre it. I don't have time to post a demo right now - but maybe later...

  • Answer ✓

    @aatish: so assuming you've added your sketch instance to a div as suggested above; you can just add the following CSS to the target div:

    <body>
        <div id="myTargetDiv" style="position: relative; width: 400px; margin: 0 auto;"></div>
    </body>
    

    ...where width should match the width of your canvas. That's a slightly old-school (but effective) approach to centering; but centering an element is well documented if you want to use a more modern approach ;)

  • @blindfish thank you, that makes a lot more sense now (and your solution works great). Appreciate your help with this!

Sign In or Register to comment.