0

I'm trying to apply a brownian movement to a HTML <li class="menu-item"> on mouse over with p5.js (instantiantion mode).

I can create an array of all items with

var menuItem = document.getElementsByClassName("menu-item");

And I can see each menu-item with console.log(menuItem[0]);

Now, I want to change behavior of each menu on mouse over. So, I have a change function:

function change() {
   console.log('changing');
}

And try to call it on mouse over:

menuItem[0].mouseOver(change); // e[0].mouseOver is not a function

and

menuItem[0].p.mouseOver(change); // Cannot read property 'mouseOver' of undefined

First example returns "is not a function" because global functions in instantiation mode must be accessed this way: p.mouseOver.

But, second example returns "Cannot read property 'mouseOver' of undefined"

What is the right way to do it? Thank you.

This is the entire script:

var sketch = function(p) {
  function change() {
    console.log('changing');
  }
  p.setup = function(){
    var menuItem = document.getElementsByClassName("menu-item");
    menuItem[0].p.mouseOver(change);
    console.log(menuItem[0]);
  };
};
new p5(sketch);
aitor
  • 2,281
  • 3
  • 22
  • 44
  • its `mouseover()` & not `mouseOver()` – dreamweiver Nov 29 '17 at 10:40
  • 1
    Reference says not: https://p5js.org/reference/#/p5.Element/mouseOver – aitor Nov 29 '17 at 10:42
  • In your code, `menuItem` is a array of plain vanilla js object and it can act on only `mouseover` event and not `mouseOver`. https://developer.mozilla.org/en-US/docs/Web/Events/mouseover . – dreamweiver Nov 29 '17 at 10:48
  • Ok. `menuItem[0].mouseover(change);` returns "mouseover is not a function" too. – aitor Nov 29 '17 at 10:57
  • Maybe I must to add a listener. I will try it. – aitor Nov 29 '17 at 11:02
  • looking at this SO, https://stackoverflow.com/questions/4347116/trigger-css-hover-with-js , i realised that you cant programmatically trigger events which are activated by user interaction, as it is not trusted event. So i have a feeling that `P5.js` created a new event by name `mouseOver` just for this reason. Now coming back to your issue, you may need to rethink on your logic. – dreamweiver Nov 29 '17 at 11:13

3 Answers3

0

This works for an item. Must be selected item as a p5 object.

p.setup = function(){
  var convoca = p.select(".itemclass");
  convoca.mouseOver(change);
};
aitor
  • 2,281
  • 3
  • 22
  • 44
0

Go into the html and write into the DOM element:

<li class="menu-item" onHover="change()"></li>

this will execute the change on hover.

Cobain Ambrose
  • 91
  • 1
  • 1
  • 8
0

I'm assuming that with p5.js you are using p5.dom.js (or p5.min.dom.js) as well.

So you called the DOM function document.getElementsByClassName("menu-item") which does give you all the menu items but as DOM objects for the DOM API (not the p5.dom API).

The p5.dom API (used hand-in-hand with p5.js) has a special function called select() and selectAll() (documentation entry for select and selectAll)

So instead of using document.getElementsByClassName("menu-item") you'd use selectAll("menu-item") to get all of the menu items for the p5.dom API.

(alternatively you could add native event listeners on the DOM functions but then the p5.dom API would not be able to be used… see event listeners here)


Now doing that you should be able to call mouseOver() on every object and have it work but in doing so, every function you attach to the object, would not know the object it is attached to.

Say we stored the items in menuItems and called menuItems[0].mouseOver(change), I found that the change function that you would make would not be able to tell which object of menuItems it was attached to.

So if, for example, function change wanted to change the color of that specific object, we could not say:

for(var i in menuItems) {
    menuItems[i].mouseOver(change)
}
function change() {
    menuItems[i].style('color', 'red')
}

because in the function change, variable i does not exist!

To solve this I also put a simple lamda function which takes in the current menuItem so it knows what to change, and returns a function that mouseOver can call!

for(var i in menuItems) {
    menuItems[i].mouseOver(change(menuItems[i]))
}

function change(target) {
    returnFunction = function(event) {
        target.style('color', 'red');
    }

    return returnFunction;
}

This is legal as mouseOver expects a function to call. We did call a function in mouseOver which returns a value returnFunction but the return value's type is a function so there is a function inside mouseOver at the end!


Fancy example below

//p5.js starts here!

function setup() {
  //these stop p5.js from looping and making a canvas
  noCanvas();
  noLoop();
  
  //selects all menu-items
  var allMenuItems = selectAll('.menu-item'); //note that you need to call the p5.dom function "select" or "selectAll" instead of the DOM function "getElementsByClassName"
  
  //iterate through all menu items
  for(var iteration in allMenuItems) {
    menuItem = allMenuItems[iteration];
    
    //at this moment it would be cool to call "mouseOver(change)" but then the function would never know which element called it so istead let's use a lamda function!
    menuItem.mouseOver(over(menuItem));//over is a lamda function which takes the current menu item and allows the function to interact with it
    //over is made below
  }
}

//function "over" that we made will take the menu item we are assigning the event to and allow us to change that same menu item
function over(target) {//fancy target variable knows which object it is set to!

  //this function changes the color of the object on mouse over
  var returnFunction = function(event) {
  
    //as this is a lamda function, the target variable seen above can be see here!
    target.style('color', color(random(0,255),random(0,255),random(0,255)));//change the target menuItem to a random color
  }
  
  //returns the function we made for the mouse over event to use, 
  return returnFunction;
}
<!-- Import p5.js to this snippet -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/addons/p5.dom.min.js"></script>
<!-- Arbitrary number of list items in a list -->
<ul>
<li><p class="menu-item"> list item 1</p></li>
<li><p class="menu-item"> list item 2</p></li>
<li><p class="menu-item"> list item 3</p></li>
<li><p class="menu-item"> list item 4</p></li>
<li><p class="menu-item"> list item 5</p></li>
<li><p class="menu-item"> list item 6</p></li>
<li><p class="menu-item"> list item 7</p></li>
<li><p class="menu-item"> list item 8</p></li>
<li><p class="menu-item"> list item 9</p></li>
<li><p class="menu-item"> list item 10</p></li>
<li><p class="menu-item"> list item 11</p></li>
<li><p class="menu-item"> list item 12</p></li>
<li><p class="menu-item"> list item 13</p></li>
<li><p class="menu-item"> list item 14</p></li>
<li><p class="menu-item"> list item 15</p></li>
</ul>

Hope this helps!

CrazyInfin8
  • 113
  • 1
  • 9