.style and .position

Hello!

Based on this example: http://p5js.org/examples/examples/Math_Arctangent.php

I am trying to create a canvas with three words, three links, that react to the mouse movement as it happens in the example. My problem is that there's a function defined here for drawing the circles, and in my case what I need is a text element. I've tried doing it both with text(' ', x, y); and with createA('#', ' ');.

In the first case, the words move according to the mouse position but I cannot turn these words into links. Also, the css is applied through a separate css sheet.

function Flickr(tx, ty) {
  this.x = tx;
  this.y = ty;
  this.angle = 0;

  this.update = function (mx, my) {
    this.angle = atan2(my - this.y, mx - this.x);
  };

  this.display = function () {
    push();
    translate(this.x, this.y);
    rotate(this.angle);
    fill(255).strokeWeight(0).textSize(36);
    text("flickr", 0, 0);
    pop();
  };
}

In the second scenario, I create the link with createA and use the .style property to apply all the styles. But, doing so, I cannot update the position of the created link since I am defining it and it has an absolute position. So it doesn't update when the mouse moves.

    function Behance(tx, ty) {
      this.x = tx;
      this.y = ty;
      this.angle = 0;

      this.update = function (mx, my) {
        this.angle = atan2(my - this.y, mx - this.x);
      };

      var link = createA('#', 'behance');
      this.display = function () {
        push();
        translate(this.x, this.y);
        rotate(this.angle);  
        link.position(0,0);
        pop();
      };
    }

Here's the entire code:

var e1, e2, e3;
var y, x;
var canvas;

function setup() {
  canvas = createCanvas(1000, 400);

  noStroke();

  x = float(width/6);
  y = float(height/2);

  e1 = new Twitter(x, y);
  e2 = new Flickr(x*2.5, y);
  e3 = new Behance(x*3.5, y);
}

function draw() {
  background(20,100,250);

  if((mouseY > 0) && (mouseY < height)) {

      e1.update(mouseX, mouseY);
      e2.update(mouseX, mouseY);
      e3.update(mouseX, mouseY);
    }

  e1.display();
  e2.display();
  e3.display();
}

function Behance(tx, ty) {
  this.x = tx;
  this.y = ty;
  this.angle = 0;

  this.update = function (mx, my) {
    this.angle = atan2(my - this.y, mx - this.x);
  };

  var link = createA('#', 'behance');
  this.display = function () {
    push();
    translate(this.x, this.y);
    rotate(this.angle);  
    link.position(0,0);
    pop();
  };
}

function Flickr(tx, ty) {
  this.x = tx;
  this.y = ty;
  this.angle = 0;

  this.update = function (mx, my) {
    this.angle = atan2(my - this.y, mx - this.x);
  };

  this.display = function () {
    push();
    translate(this.x, this.y);
    rotate(this.angle);
    fill(255).strokeWeight(0).textSize(36);
    text("flickr", 0, 0);
    pop();
  };
}

function Twitter(tx, ty) {
  this.x = tx;
  this.y = ty;
  this.angle = 0;

  this.update = function (mx, my) {
    this.angle = atan2(my - this.y, mx - this.x);
  };

  this.display = function () {
    push();
    translate(this.x, this.y);
    rotate(this.angle);
    fill(255).strokeWeight(0).textSize(36);
    text("twitter", 0, 0);
    pop();
  };
}

I would appreciate any help. Thank you!

Answers

  • edited June 2016 Answer ✓

    I don't normally post working code; but you're close enough to the desired result; though have over-complicated things significantly (see inline comments for explanations of changes):

    "use strict";
    
    //TODO: you could store all your objects in an array
    // particularly if you're likely to have more than 3...
    var e1, e2, e3;
    var canvas;
    
    function setup() {
      canvas = createCanvas(1000, 400);
    
      noStroke();
     // these variables are only required during setup: don't make them global
      var x = float(width/6);
      var y = float(height/2);
    
      //TODO: populate URLS
      e1 = new Rotator(x, y, "twitter", "http:" + "//twitter.com");
      e2 = new Rotator(x*2.5, y, "flickr");
      e3 = new Rotator(x*3.5, y, "behance");
    }
    
    function draw() {
      background(20,100,250);
    
      if((mouseY > 0) && (mouseY < height)) {
          e1.update(mouseX, mouseY);
          e2.update(mouseX, mouseY);
          e3.update(mouseX, mouseY);
        }
    
      e1.display();
      e2.display();
      e3.display();
    }
    
    
    function mouseClicked(evt) {
      e1.respondToMouseClick(evt.x, evt.y);
      e2.respondToMouseClick(evt.x, evt.y);
      e3.respondToMouseClick(evt.x, evt.y);
    }
    
    
    
    
    // Make things simpler (avoid duplication of code!) 
    // by using a single configurable Object
    function Rotator(x, y, label, URL) {
        this.x = x;
        this.y = y;
        this.label = label;
        this.url = URL;
        this.angle = 0;
    }
    
    
    // attach 'methods' to the prototype 
    Rotator.prototype.update = function(mx, my) {
        // adjust angle to change which side of the text points to the mouse
        // -HALF_PI gets the top pointing to mouse.  +HALF_PI will be the bottom.
        this.angle = atan2(my - this.y, mx - this.x) - HALF_PI;
    };
    
    
    Rotator.prototype.display = function () {
        push();
          translate(this.x, this.y);
    
          // displays hit area for debugging
          // delete if undesirable
          fill('#ff9900');
          ellipse(0,0,150,150)
    
    
          rotate(this.angle);
          fill(255).strokeWeight(0).textSize(36);
          // rotate around the text center!
          textAlign(CENTER, CENTER);
          text(this.label, 0, 0);
        pop();
    };
    
    
    Rotator.prototype.respondToMouseClick = function(mx, my) {
        var delta = dist(this.x, this.y, mx, my);
        // 75 is an arbitrary value.
        // You could set this value in the constructor
        // based on the value of the text;
        // or take a different approach to hit detection 
        // (current approach is the simplest)
        if(delta < 75) {
            openLink(this.url);
        }
    }
    
    // adapted from: forum.processing.org/two/discussion/8809/link-function#Comment_33474
    function openLink(url, winName, options) {
      if(url) {
        winName && open(url, winName, options) || (location = url);    
      }
      else {
        console.warn("no URL specified");
      }
    }
    
  • Thank you so much for this, I tend to make things more complicated than they are. There's only one thing I had to change:

    e1 = new Rotator(x, y, "twitter", "https://www.twitter.com");
    e2 = new Rotator(x*2.5, y, "flickr", "https://www.flickr.com");
    e3 = new Rotator(x*3.5, y, "behance", "https://www.behance.net");
    

    Otherwise the links wouldn't work: <a href="#" target="_blank" rel="nofollow">http://twitter.com</a>;

    I also tried changing the " " for ' ' and got the same message: Error code explanation: 404 = Nothing matches the given URI. Is there any way of adding the target and options? Are they necessary here?

  • @striuk sorry: I forgot that the forum mangles urls in code and converts them to html links. Have edited my example to avoid this... The links will open in the same browser window as the running sketch, but as GoToLoop implied if you want a new window you should be able to pass extra parameters to openLink() to achieve this...

  • @blindfish okay, I get it now, I'll add the rest of things to openLink() then. Thank you again !

Sign In or Register to comment.