Search code examples
javascripthtmlcanvasrandomjspsych

Is there a way to generate a random contrast level on html canvas?


I am trying to present this shape as a stimulus in a behavioral experiment. I wantthe image to have a random contrast level between 0 and 1. I am trying to use Math.random() for that but when I run this in Chrome the shape flickers when it is presented on the screen. Is there a way to present a stable shape with randomly generated contrast levels?

drawFunc: function gabor() {
            context = jsPsych.currentTrial().context;
            context.beginPath();
            const gradLength = 100;
            const my_gradient  = context.createLinearGradient(850, 0, 1050, 0);
            my_gradient.addColorStop(0,'rgb(0, 0, 0)');
            my_gradient.addColorStop(0.05,'rgb(255, 255, 255)');
            my_gradient.addColorStop(0.1,'rgb(0, 0, 0)');
            my_gradient.addColorStop(0.15,'rgb(255, 255, 255)');
            my_gradient.addColorStop(0.2,'rgb(0, 0, 0)');
            my_gradient.addColorStop(0.25,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.3,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.35,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.4,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.45,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.5,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.55,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.6,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.65,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.7,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.75,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.8,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.85,"rgb(255, 255, 255)");
            my_gradient.addColorStop(0.9,"rgb(0, 0, 0)");
            my_gradient.addColorStop(0.95,"rgb(255, 255, 255)");
            my_gradient.addColorStop(1,"rgb(0, 0, 0)");
            var result1 = Math.random();
            context.filter = 'contrast('+ result1 +')';
            context.fillStyle=my_gradient;
            context.fillRect(950,300,gradLength,gradLength);
            context.stroke();

Solution

  • Use a setup function to get the constants

    • Create the gradient once
    • Get the context once.

    Create contrast once using a function. See example

    Remove setup code from draw function. Remove random contrast value from draw function.

    Remove redundant code

    • No need for context.beginPath(); as you draw the using fillRect
    • No need for context.stroke(). Not sure why you are calling stroke as you have not defined a path after the beginPath call
    • Why assign a named function gabor to object property drawFunc Do you call the function using its name or the property. Which ever you use makes the other redundent.

    Example

    setup() {
        this.ctx = jsPsych.currentTrial().context;
        const g = this.gradient = this.ctx.createLinearGradient(850, 0, 1050, 0);
        const bands = 10, colors = ["#000", "#FFF"];
        const stops = bands * colors.length;
        var pos = 0;
        while (pos <= stops) {
            g.addColorStop(pos / stops, colors[pos % colors.length]);
            pos++;
        }
    },  
    randomContrast() {
        this.contrast = Math.Random();
        this.drawFunc();
    },
    drawFunc() {
        const ctx = this.ctx;
        ctx.filter = 'contrast('+ this.contrast +')';
        ctx.fillStyle = this.gradient;
        ctx.fillRect(950, 300, 100, 100);
    },
    

    Call setup once, then call randomContrast to change the contrast. If you need to redraw the gradient without changing the contrast call drawFunc