2

I have this idea, in which you can only see blackness on the site, but when you hover on it with your mouse it shows a radial gradient white circle that reveals the menu items beneath it, such as "contact", "info", and "products". And when you click on "products" all the items on the page appears, but still they are hidden under the blackness and only show when you hover on it. If you click on any of the products, you can go to product page through the a tag link.

So I get the both parts - 1) reveal things with gradient circle, and 2) products shown after clicking on "products" - to work, but the canvas part with the gradient just get stuck when the products appear. That's probably because I tried to do it in a hacky way by separating these two interactions, as follows:

<!DOCTYPE HTML>
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="./assets/stylesheet/normalize.css">
    <link rel="stylesheet" type="text/css" href="./assets/stylesheet/style.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
  </head>
  <body>
    <div id="menu">
      <div class="menu-item" id="products"><a>Products</a></div>
      <div class="menu-item" id="contact"><a href="./contact.html">News</a></div>
    </div>
    <script>
      // create a full screen canvas
      var canvas = document.createElement("canvas");
      canvas.style.position = "absolute";
      canvas.style.left     = "0px";
      canvas.style.top      = "0px";
      canvas.style.zIndex   = 10;
      canvas.width          = window.innerWidth;
      canvas.height         = window.innerHeight;
      document.body.appendChild(canvas);
      // var to hold context
      var ctx;

      // load an image
      var image = new Image();
      image.src = "./assets/images/white.jpg";

      // add resize event
      var resize = function(){
          canvas.width   = window.innerWidth;
          canvas.height  = window.innerHeight;
          ctx            = canvas.getContext("2d");
      }
      // add mouse event. Because it is full screen no need to bother with offsets
      var mouse = function(event){
          posX = event.clientX;
          posY = event.clientY;
      }
      // incase the canvas size is changed
      window.addEventListener("resize",resize);

      // listen to the mouse move
      canvas.addEventListener("mousemove",mouse);

      // Call resize as that gets our context
      resize();

      // define the gradient
      var cirRadius = 300;

      var posX = 100; // this will be set by the mouse
      var posY = 100;
      var RGB = [11,11,11] ; // black any values from 0 to 255
      // var alphas = [0,0,0.2,0.5,0.9,0.95,1]; // zero is transparent one is not
      var alphas = [0,0,0.1,0.5,1];

      // the update function
      var update = function(){
          if(ctx){  // make sure all is in order..
              if(image.complete){ // draw the image when it is ready
                  ctx.drawImage(image,0,0,canvas.width,canvas.height)
              }else{ // while waiting for image clear the canvas
                  ctx.clearRect(0,0,canvas.width,canvas.height);
              }
              // create gradient
              var grad = ctx.createRadialGradient(posX,posY,0,posX,posY,cirRadius);
              // add colour stops
              var len = alphas.length-1;
              alphas.forEach((a,i) => {
                   grad.addColorStop(i/len,`rgba(${RGB[0]},${RGB[1]},${RGB[2]},${a})`);
              });
              // set fill style to gradient
              ctx.fillStyle = grad;
              // render that gradient
              ctx.fillRect(0,0,canvas.width,canvas.height);
          }
          requestAnimationFrame(update); // keep doing it till cows come home.

      }

      // start it all happening;
      requestAnimationFrame(update);

    </script>

    <script>
      $("#products").click(function(){

        $("#products").remove();

        var diagram = document.createElement("div");
        diagram.style.position = "absolute";
        diagram.style.left = "0px";
        diagram.style.top = "0px"
        diagram.style.zIndex  = 100;
        diagram.style.width = window.innerWidth + "px";
        diagram.style.height = window.innerHeight + "px";
        document.body.appendChild(diagram);

        var products = [{
                      titleShort: "Black",
                      mainImage: "N/A",
                      link: "./black.html"
                    }, {
                      titleShort: "White",
                      mainImage: "N/A",
                      link: "./white.html"
                    }, {
                      titleShort: "Red",
                      mainImage: "N/A",
                      link: "./red.html"
                    }, {
                      titleShort: "Blue",
                      mainImage: "N/A",
                      link: "./blue.html"
                    }]

        for (var i = 0; i < products.length; i++) {
          var product = document.createElement("div");
          diagram.appendChild(product);
          productstyle.position = "absolute";
          product.style.width = "120px";
          product.style.height = "50px";
          product.style.top = i * 100 + "px";
          product.style.left = i * 100 + "px";
          product.style.textAlign = "center";
          var circle = document.createElement("a");
          circle.style.width = "15px";
          circle.style.height = "15px";
          circle.style.borderRadius = "50%";
          circle.style.backgroundColor = "black";
          circle.style.marginLeft = "auto";
          circle.style.marginRight = "auto";
          circle.href = products[i].link;
          product.appendChild(circle);
        }

      });

    </script>

  </body>
</html>

Note: all the products are just represented by the dots/circles for sake of convenience.

It's probably best if I merge two parts into one canvas. For example, right now we have that white image as the background for the canvas, if in some ways we can update the image with the products? But I'm very new to canvas and therefore not sure how to do this. Any other suggestions welcome as well.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 1
    Why use canvas for this at all? I would use CSS's `border-radius`, along with simply changing the display, like `.someClassName{display: none;}` and `.someClassName:hover{display:block;}`. – StackSlave May 03 '16 at 00:29
  • @PHPglue thanks for your input but I'm not sure you understand what I'm trying to do...I want all the items to appear, although they are hidden under the blackness. When you hover, you "see through" the blackness to see the items. In your method, how would the gradient circle reveal the blackness? – practicemakesperfect May 03 '16 at 13:42
  • @markE Please remove the duplicate mark; this is not a duplicate of the same question. In the other question you provide, a user don't interact with the image in the background at all and the image remains the same through out; in my question, the user can actually click on different part of the background image to get to different pages. – practicemakesperfect May 03 '16 at 18:01
  • @practicemakesperfect. IMHO, it seems like the [dup question](http://stackoverflow.com/questions/32441576/html-canvas-spotlight-effect) answers your question title (gradient circle reveal) and the rest of your question is asking for design advice on how to click-link to your product pages -- But we don't do design advice on Stackoverflow! Anyway, against my opinion ... dup flag removed. :-) – markE May 03 '16 at 18:30
  • @markE Thanks! Yes, it's hard to summarize it into a title. But I don't think it's a design question. Currently, if you implement what I have, the gradient get stuck as the products show up, because the products appear on top of the canvas. I wonder how I can hide the products under the canvas, but still able to click on things. – practicemakesperfect May 03 '16 at 18:46

1 Answers1

0

You could use a div (a) with display none, border radius 50%, an insanely high value for border (solid, black), position fixed and a high z-index. Then use a second div (b) with width 100%, height 100%, background black and also position fixed and a high z-index.

Your "hotspots" have a mouseon handler on it on which you set the position of "a" to the position of the hotspot, set it to display block and set "b" to display none.

A mouseout event then does everything backwards.

Now most people would mislike the idea of a imense border, but hey: it's not like it takes more traffic than any other border and it should be way more performant than to use canvases aswell as way less code.

P.s.: sry i can't provide any code samples since I'm on mobile. This also explains the typos. If you like the idea I (or someone in the comments) can write you a quick fiddle. Also if you are using a js library (like jQuery for example) we can consider this in the snippets.

Edit 1: sorry, I didn't noticed your code already contained the jQuery include. This should make the js part just a few lines... Also with a little extra code you can have transitions, gradients,.... any fancyness you like

LukasKroess
  • 125
  • 2
  • 13