Playground fun and stuff

This is to talk about stuff u made on the playground :eyeglasses: :sunglasses:

3 Likes

i made somthing that has blanket patterns

2 Likes

Cool! If you want to post a screenshot of the code, I’d love to take a look at what you made!

1 Like

ok :wink: :wink: :smiley: wait 1 minute

5 Likes

Hey @Grasshopper_Ben i did this today

(all by myself do u like it :hugs: :grin: :sweat_smile: :laughing: :star_struck:

6 Likes

Those look great! Very cool.

2 Likes

thank you a lot [quote=“Grasshopper_Ben, post:7, topic:13338, full:true”]
Those look great! Very cool.
[/quote]

:grin:

1 Like

my last snipped will create a given number of ellipses and change position, size and color, when the screen is tapped. it works fine and looks nice, but …

… there’s a problem: it works only several times, dependent on the number of ellipses. 10 ellipses will show the expected reaction 9 times, 20 ellipses only 4 times. the code is below (i’ve added some comments for better understanding).

is this a memory problem? it shouldn’t since the event handler does not create new objects, but only change existing attributes. interesting, this happen to me on my handy using the grasshopper app and also on my pc at https://learn.grasshopper.app/playground

2 Likes

Hey there, very cool program!

It’s not a memory problem, though it’s possible you’re hitting the 500 function call limit that we placed on the call stack. We put this limit there to prevent users from getting stuck in infinite loops, but it can sometimes also prevent larger programs from running properly in the code playground.

I don’t think this is the issue, but if it is, try putting disableLimits() at the top of your program to remove this limit.

The issue could be elsewhere though. Try walking through your code step by step as if you’re the computer. What are you being asked to do at each step? Where are you drawing the ellipses? Are any being drawn outside the webview window?

Hope this helps! I’m looking forward to seeing the code again once you finish debugging!
Ben

1 Like

disableLimits();
that did solve the problem.

thank you so much, now I can click in quick succession, and that looks good.
i feel encouraged to make more such snippets. :sunglasses:

2 Likes


interesting… how can sth i assigned to {} be not equal to it, no matter i use ‘===’ or ‘==’ ?

1 Like

Glad to hear the fix was so simple, and great question! The answer might seem a little complicated at first.

When you assign a primitive value, like a number or a string, to a variable, that variable then directly holds that value. So this code would print true:

let num = 5
console.log(num === 5) // prints true

When you assign an object to a variable, the computer behaves a little differently. Instead of giving the variable a value to hold, you’re instead giving the variable the address of a place in the computer’s memory where the object is stored. This is called a reference.

That’s why this returns false:

let foo1 = {
    bar: 'baz'
}

let foo2 = {
    bar: 'baz'
}

console.log(foo1 === foo2) // returns false

foo1 and foo2 aren’t directly holding objects. They are actually holding references to where the objects are held in memory, and those references are different.

There’s a really good newsletter I’ve found recently called Just JavaScript that I think you’d benefit from. It’s by Dan Abramov (creator of React) and Maggie Appleton (illustrator). The 7th email they send out goes into this topic.

Good luck!
Ben

1 Like

thank you so much again for the time you are spending for us grasshopper noobies =)
yeah i don’t know how i could forgot the thing with the pointers, but it’s good to have it back in my consiousness. How about function calls and object parameters, are they called by reference or by value like primitive parameters - i mean, when I for instance change the object parameter’s property values within the function, will it change the original object’s property values?

as for now and my last experiments on the grasshopper playground - i have been playing with gradients and transitions with duration (and finally with nested array bar charts). it looks like js needs a long time for calculations when calling .transition() for shapes with gradients.

if in the snippet shown below, you click on the upper background, the balls will elasticly move around and have a new position and size and (instead of color) a new color gradient. so far so good, the size and position transition works indeed fine, but the new gradients are shown only after the balls have reached their new size and position, no matter i use a second .transition() and .duration(0) or not.

if i dont call .transition() a second time it’s even worse: the balls will disapear immediately for 5000 milliseconds (the duration time i choosed) and then will suddently appear again at their new position with new size and gradient - no transition will be seen. the second duration(0) call is also needed since without, the transition of position and size can be seen but after the balls have reached their final position (and have their new size), they would simply disapear for another 5000 milliseconds, and then suddenly appear again with their new color gradients.

the best result i could get is with a second call of .transition() and .duration(0) before the call of attr('fill', ...). it seems there is simply no smooth transition of gradients, whereas simple color transitions (without gradient) work fine.

4 Likes

Once again, very nice work! I’m in awe!

While I can’t be totally sure without playing with the code myself, the issue is probably some complication with having a transition inside a for loop. There’s a relevant stack overflow post about it here.

You can also dig into the D3 docs here on Github.

Good luck!
Ben

1 Like

Thx for answering.

As for the ‘relevant overflow post’ you linked - the code there works fine here, i only added “http:” in the -tag. And of course i shifted var now=d3.select('#cc'); one line above the loop - but it even works fine when i let it in the loop (what makes no sense).

Of course I can let you play with the code, i only fear you have no time… here we go:
EDIT#1: I don’t know why but the spoiler does not work proper, maybe the code is too long…
EDIT#2: if you use it in a html-doc you will need a div element with id=“gernots-svg-container”:

<div id="gernots-svg-container"></div>

    if (document.getElementById('gernots-svg-container') === null) 
      disableLimits();                                                  // disable the 500 function call limit
    // ---------------------------------------------------------------------------------------
    const scrWidth = 230;	                                            // screen width at learn.grasshopper.app
    const scrHeight = 400;	                                            // screen height at learn.grasshopper.app
    const rMax = 10;		                                            // max radius of the balls
    const rMin = 6;		                                                // min radius of the balls
    const number = 20;                                                  // number of balls
    const time = 5000;     	                                            // duration of transition
    const colors = [                                                    // const array with color pairs for the ball's gradients
      ['orangered', 'darkred'], 
      ['pink', 'deeppink'], 
      ['orange', 'red'], 
      ['lime', 'green'], 
      ['yellow', 'orangered'],
      ['purple', 'violett']
    ];
    const scrGradient = {                                               // gradient for the screen
      type: 'linear',
      id: 'scr',
      geo: [0.2, 0, 0.8, 1],
      offset: [0, 1],
      color: ['blue', 'midnightblue'],
      opacity: [1, 1]
    }
    const ballGradient = {                                              // Template, which holds the const properties
      type: 'radial',
      id: '',                                                           // id is not constant and will get assign unique values to
      geo: [0.35, 0.35, 0.65],
      offset: [0, 1],
      color: [],                                                        // color is not constant and will store a unique pair of colors
      opacity: [1, 0.5]
    }
    // -------------------------------------------------------------------------------------------------------------------------------------
    if (document.getElementById('gernots-svg-container') !== null) {
      var svg = d3
        .select('#gernots-svg-container').append('svg')
        .attr('width', scrWidth).attr('height', scrHeight);
    }
    var defs = svg.append('defs');
    var fillBall = [];
    var balls = [];
    var gradients = [];                                                 // nested array to store the gradientID
    var gradientsAssigned = 0;                                          // until now gradients never been assigned
    // -------------------------------------------------------------------------------------------------------------------------------------
    function addGradient(gradient) {                                    // add a gradient to defs of svg
      let newGradient = defs
          .append(gradient.type + 'Gradient')
          .attr('id', gradient.id);
      if (gradient.type === 'radial') {                                 // if gradient.type is 'radial'
        newGradient                                                     // set x- and y-center and the radius of the gradient
          .attr('cx', gradient.geo[0])
          .attr('cy', gradient.geo[1])
          .attr('r', gradient.geo[2])  
      } else if (gradient.type === 'linear') {                          // if gradient.type is 'linear'
        newGradient                                                     // set start- and end-points of the gradient
          .attr('x1', gradient.geo[0])
          .attr('y1', gradient.geo[1])
          .attr('x2', gradient.geo[2])
          .attr('y2', gradient.geo[3])
      }
      for (let i = 0; i < gradient.offset.length; i++) {                // for every given stop
        newGradient.append('stop')                                      // add the stop to the new gradient
          .attr('offset', gradient.offset[i])                           // store their attr values
          .attr('stop-color', gradient.color[i])
          .attr('opacity', gradient.opacity[i]);
      }
      return 'url(#' + gradient.id + ')';                               // RETURN VALUE is used to call .attr('fill', RETURN VALUE)
    }
    // -------------------------------------------------------------------------------------------------------------------------------------
    function addBallGradients() {
    // every element in the const array 'colors' (see const declaration section above) is a unique pair of colors for the balls. for every
    // element in 'colors' a unique gradient will be created, where the property 'color' will hold the unique pair of colors, and 'id' will
    // hold a unique identifier (a letter followed by a counter). the other properties will stay constant for every gradient.
    // the gradient will be added to 'svg.defs' and a string "'url(#' + id + ')'" will be stored in the var array 'fillBall'
      var gradient = ballGradient;                                      // assign the const values to the properties
      for (let c = 0; c < colors.length; c++) {                         // assign the unique values to:
        gradient.id = 'ball' + c;                                       //   - the 'id' property
        gradient.color = colors[c];                                     //   - the 'color' property
        fillBall[c] = addGradient(gradient);                            // append the gradient to svg.defs and add the returned string
      }                                                                 // to the var array 'fillBall'. string pattern is "'url(#' + id + ')'"
    }
    // -------------------------------------------------------------------------------------------------------------------------------------
    var scr =                                                           // variable 'scr' will be used to create a click event handler
        svg.append('rect')                                            // inside the svg-container draw the background rectangle
        .attr('width', scrWidth).attr('height', scrHeight)            // use const scrWidth and scrHeight declared above
        .attr('fill', addGradient(scrGradient));                      // use const scrGradient declared above

    addBallGradients();
    var gradientID;
    var ball;
    var r;
    gradients[0] = [];                                                // 1. element of array 'gradients' is an empty array

    for (let i = 0; i < number; i++) {

      r = rMin + Math.floor(Math.random() * (rMax - rMin) );          // pick random radius r in the range rMin - rMax
      gradientID = Math.floor(Math.random() * colors.length);         // pick a random member of the var array 'fillBall' and ...
      ball = svg.append('circle')                                     // inside the svg-container draw a ball with ...
        .attr('cx',r + Math.floor(Math.random() * (scrWidth - 2 * r)))// ... random x coordinate of center and ...
        .attr('cy',r + Math.floor(Math.random() * (scrHeight - 2 * r)))// ... random y coordinate of center and with ...
        .attr('r', r)                                                 // the random radius r
        .attr('fill',fillBall[gradientID]);                           // ... fill the ball with that color gradient
      gradients[0][i] = gradientID;                                   // store the used gradient index in gradients[0][i]

      balls[i] = ball;                                                // add the ball to the array variable 'balls'
    }

    gradientsAssigned = 1;                                            // gradients were assigned once until now

    scr.on('click', () => {                                           // event handler

      gradients.push([]);                                             // add a new element (empty array) to array variable 'gradients'

      for (let i = 0; i < number; i++) {

        r = rMin + Math.floor(Math.random() * (rMax - rMin) );        // pick random radius r in the range rMin - rMax
        do {
          gradientID = Math.floor(Math.random() * colors.length);     // pick a random member of the var array 'fillBall' and
        } while (gradientID === gradients[gradientsAssigned - 1][i]); // make sure that it's not the same as before the click
        balls[i].transition().duration(time).ease(d3.easeElastic)
          .attr('cx',r + Math.floor(Math.random() * (scrWidth - 2 * r)))// ... random x coordinate of center and ...
          .attr('cy',r + Math.floor(Math.random() * (scrHeight - 2 * r)))// ... random y coordinate of center and with ...
          .attr('r', r)                                               // the random radius r
          .transition().duration(0)
          .attr('fill',fillBall[gradientID]);
        gradients[gradientsAssigned][i] = gradientID;                 // store the used gradient index in gradients[gradientsAssigned][i]
      }
      gradientsAssigned++;                                            // gradients were assigned one more time
    });
3 Likes

Thanks! I’ll take a look at it when I find some free time.

2 Likes

I deleted grasshopper because it was misbehaving and I believed if I reinstalled it, my progress would return. Well… it didn’t and am in animations pls help I can’t start again

I am not getting this recursive code

@Grasshopper_Ben can you please explain it

1 Like

Hey, @Grasshopper_Ben
I made this all by myself. Do you like it?

1 Like