Functions in Graphics Object

Hello Folks:

Have a look at the following code: var element

function drawarectangle(x, y, w, h){
  rect(x, y, w, h);
}

function setup() {
  createCanvas(500, 500);
  background(0);

  element = createGraphics(400,400);
  element.background(100);
  element.fill(255);
  element.drawarectangle(100,100,200,200);
}

function draw() {
  image(element, 50, 50);
}

ok. so basically i want to call a function inside a Graphics Object. For the sake of the easiness I wrote a completely useless function call "drawarectagle" and I want to call this function inside the graphics object "element". How can I do this, because I cant just say element.drawarectangle(100,100,200,200);?

Answers

  • I suppose you could do this:

    element.drawarectangle = function(x, y, w, h){
      rect(x, y, w, h);
    }
    

    element.drawarectangle(100,100,200,200);

    But that feels a little hacky. Why don't you just change your drawarectangle() function to take an element argument?

    function drawarectangle(element, x, y, w, h){
      element.rect(x, y, w, h);
    }
    
    drawarectangle(element, 100,100,200,200);
    
  • edited March 2018

    https://OpenProcessing.org/sketch/528626

    /**
     * Prototype Graphics (v1.0)
     * GoToLoop (2018-Mar-28)
     *
     * Forum.Processing.org/two/discussion/27465/functions-in-graphics-object#Item_2
     *
     * OpenProcessing.org/sketch/528626
     */
    
    "use strict";
    
    let pg;
    
    function setup() {
      colorMode(RGB).rectMode(CORNER).noLoop();
      fill('yellow').stroke('red').strokeWeight(2.5);
    
      p5.prototype.drawRectangle = function (...args) {
        return this.rect(...args);
      };
    
      p5.prototype.drawRectangle = p5.prototype.rect; // shorter alternative
    
      pg = createGraphics(width>>1, height>>1);
      pg.colorMode(RGB).rectMode(CORNER);
      pg.fill('green').noStroke();
      pg.drawRectangle(pg.width>>2, pg.height>>2, pg.width>>1, pg.height>>1);
    }
    
    function draw() {
      background(0o50).drawRectangle(width>>2, height>>2, width>>2, height>>2);
      image(pg, width>>1, height>>1);
    }
    
  • edited March 2018

    But... That works for the madeup function i created, but not for all functions. or am i misstaken?

  • Who are you asking that question?

    And what happened when you tried?

  • edited March 2018

    We can only give out examples based on what you had already told us. :-@
    If your needs are more complex, you should provide/post more detailed info about them. :-\"

    p5.prototype.drawRectangle = function (...args) {
      return this.rect(...args);
    };
    

    The function above is merely a very basic template on how to add methods to both p5.js' p5 & p5.Graphics classes via JS' prototype inheritance chain: :ar!

    1. https://p5js.org/reference/#/p5.Graphics
    2. https://Developer.Mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
  • edited March 2018

    In your given example, drawRectangle() merely acts as an alias to p5::rect().

    That's why just assigning rect() to drawRectangle() works as well: :-j
    p5.prototype.drawRectangle = p5.prototype.rect;

    But if you've got more complex stuff to add to p5.js' API in mind, you should consider creating your own separate 3rd-party library for it. *-:)

  • edited March 2018

    Ok. so here is one of the functions i want to draw in the graphics element:

    function VSlider(x, y, Lenght, Max, Value, Active) {
        var val = map(Value, 100, 0, y, y+Lenght);
        textSize(20);
        fill(150);
        stroke(0);
        strokeWeight(3);
    
        rect(x-5, y, 10, Lenght, 5);
    
        fill(0);
        rect(x-12, val-5, 24, 10, 2);
    
      if (mouseX < x+12 && mouseX > x-12 && mouseY > val-4 && mouseY < val+4 && mouseIsPressed){ 
        Active=true;}
    
      if (Active===true && mouseIsPressed===false){
        Active=false;}              
    
      if (Active) {
            val=mouseY;}
    
      if (val < y){
        val = y;}
    
        if (val > y+Lenght){
            val = y+Lenght}
    
        Value = map(val, y, y+Lenght, 100, 0)
    
      return {V:Value, A:Active};
    }
    

    So it creates a vertical slider. I looked at the links, but I can't really see helpful tips that I understand X_X

  • edited March 2018

    Some notes about naming convention for both Java & JS: L-)

    • Variables & functions should follow the lowerCamelCase.
    • So your function VSlider() should be renamed as vSlider().
    • And its parameters: Lenght, Max, Value, Active.
    • Should be instead: length, max, value, active.
    • Notice also that length is the correct word, not lenght.
  • edited March 2018

    Even though you could force your function to become a method for p5.js' p5 & p5.Graphics classes:
    p5.prototype.vSlider = function (length, max, value, active) {};

    Plus prefixing all the p5.js API used there w/ this.:
    For example, textSize(20); becomes this.textSize(20);
    And mouseIsPressed becomes this.mouseIsPressed, and so on.

    Your function is completely outta place as a member of p5.js API for various reasons: :-O

    • It changes fill, stroke, font size, etc, instead of just using their current values.
    • It even checks out mouse coordinates & state!
    • And worse, it returns an object representing its current state.
    • And that object needs to be passed over & over as its 2 last parameters!

    Instead create a class as a proper place to store & manage those 2 states w/ methods: *-:)
    https://Developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

  • edited March 2018
  • edited March 2018

    Ok. That answers my question. I wanted to transform the vSlider functions anyways and i am going to do it now. but why?

    Why is bad if I change fill,stroke,font sizes etc.?

    Why is it bad if my function checks mouse position?

    Why is returning an object bad?

    And why should i follow lowerCamelCase?

    But otherwise: Thank you!

  • Yeah. But why not just create my own funtion? Just because I can :-\"

  • edited March 2018 Answer ✓

    You're mixing up functions, methods & API as if those 3 terms were the same thing development-wise.

    You've asked about turning your custom functions into methods of p5.js' API.

    However, it turns out your function acts as a whole GUI slider "library", completely at odds w/the rest of p5.js' API: https://p5js.org/reference/

    Your vertical slider function even got 2 states which it returns & expects them to be re-passed again when it is re-invoked! @-)

    And your function doesn't respect & even mutates canvas' current attributes like fill, stroke, etc.

    Therefore, even though you can hack your way for it, your function is completely unfit as a p5.js API method, in comparison to the type of features p5.js API offers! 8-X

    As I had already advised you, you should instead create a class to store those 2 state values and make your function a method of that class. :-B

  • edited March 2018

    Do you mean something like this?

    class vSlider {
        constructor(x, y, length, value, active){
            this.x = x
            this.y = y
            this.length = length
            this.value = value
            this.active = active
        }
    
        draw(){
            fill(150)
            rect(this.x-5, this.y, 10, this.length, 5);
        }
    
        slide(){
            this.val = map(this.value, 0, 100, this.y + this.length, this.y)
    
            fill(0)     
            rect(this.x-16, this.val-6, 32, 12, 2)
    
            if (mouseX < this.x+12 && mouseX > this.x-12 && mouseY > this.val-4 && mouseY < this.val+4 && mouseIsPressed){ 
                this.active=true}
    
            if (this.active===true && mouseIsPressed===false){
                this.active = false}              
    
            if (this.active) {
                this.val = mouseY}
    
            if (this.val < this.y){
                this.val = this.y;}
    
            if (this.val > this.y + this.length){
                this.val = this.y + this.length}
    
            this.value = map(this.val, this.y, this.y + this.length, 100, 0)
        }
    
        value(){
            return(this.value)
        }
    
        active(){
            return(this.active)
        }
    
    }
    

    and then u can activate it with this:

    data = {V: 0, A:false}
    
    slider = new vSlider(width/2-20, 10, height/2-30, data.V, data.A)
    slider.draw()
    slider.slide()
    data.V = slider.value
    data.A = slider.active
    
Sign In or Register to comment.