Change color of the scenery with button

Asked

Viewed 307 times

9

I am creating a scenario with Parallax and wanted to simulate color change in the mountains, for that, the color will be chosen by the user. I have 3 buttons for the effect.

HTML

My problem is I don’t know how I’m gonna make the mountains change color since they start with a fixed color.

HTML is practically done:

<div id="game">
<button class="user" data-name="red">Red</button>
<button class="user" data-name="green">Green</button>
<button class="user" data-name="blue">Blue</button>
<button id="test">Change Color</button>

My question is how I’m going to get the mountains to start with the color selected, I don’t even know if it makes sense to have the button "Change Color".

The Javascript code of the setup is as follows:

id="rendered-js">
      (function () {
  var Montanha, MontanhaRange, dt, MontanhaRanges, janela;

  janela = Sketch.create();

  janela.mouse.x = janela.width / 10;

  janela.mouse.y = janela.height;

  MontanhaRanges = [];

  dt = 1;
  p = 90;

  Montanha = function (config) {
    return this.reset(config);
  };

$(document).ready(function() {
    var user = "none";
    $(".user").click(function() {
        user = $(this).attr("data-name");
    });
        $("#test").click(function() {
        window.location.reload();
        p = 240
    });
});

// Montanhas

  Montanha.prototype.reset = function (config) {
    this.layer = config.layer;
    this.x = config.x;
    this.y = config.y;
    this.width = config.width;
    this.height = config.height;
    return this.color = config.color;
  };

  // Montanha tamanho

  MontanhaRange = function (config) {
    this.x = 0;
    this.Montanhas = [];
    this.layer = config.layer;
    this.width = {
      min: config.width.min,
      max: config.width.max };

    this.height = {
      min: config.height.min,
      max: config.height.max };

    this.speed = config.speed;
    this.color = config.color;
    this.populate();
    return this;
  };

  MontanhaRange.prototype.populate = function () {
    var newHeight, newWidth, results, totalWidth;
    totalWidth = 0;
    results = [];
    while (totalWidth <= janela.width + this.width.max * 4) {if (window.CP.shouldStopExecution(0)) break;
      newWidth = round(random(this.width.min, this.width.max));
      newHeight = round(random(this.height.min, this.height.max));
      this.Montanhas.push(new Montanha({
        layer: this.layer,
        x: this.Montanhas.length === 0 ? 0 : this.Montanhas[this.Montanhas.length - 1].x + this.Montanhas[this.Montanhas.length - 1].width,
        y: janela.height - newHeight,
        width: newWidth,
        height: newHeight,
        color: this.color }));

      results.push(totalWidth += newWidth);
    }window.CP.exitedLoop(0);
    return results;
  };

  MontanhaRange.prototype.update = function () {
    var firstMontanha, lastMontanha, newHeight, newWidth;
    this.x -= janela.mouse.x * this.speed * dt;
    firstMontanha = this.Montanhas[0];
    if (firstMontanha.width + firstMontanha.x + this.x < -this.width.max) {
      newWidth = round(random(this.width.min, this.width.max));
      newHeight = round(random(this.height.min, this.height.max));
      lastMontanha = this.Montanhas[this.Montanhas.length - 1];
      firstMontanha.reset({
        layer: this.layer,
        x: lastMontanha.x + lastMontanha.width,
        y: janela.height - newHeight,
        width: newWidth,
        height: newHeight,
        color: this.color });

      return this.Montanhas.push(this.Montanhas.shift());
    }
  };

  MontanhaRange.prototype.render = function () {
    var c, d, i, j, pointCount, ref;
    janela.save();
    janela.translate(this.x, (janela.height - janela.mouse.y) / 20 * this.layer);
    janela.beginPath();
    pointCount = this.Montanhas.length;
    janela.moveTo(this.Montanhas[0].x, this.Montanhas[0].y);
    for (i = j = 0, ref = pointCount - 2; j <= ref; i = j += 1) {if (window.CP.shouldStopExecution(1)) break;
      c = (this.Montanhas[i].x + this.Montanhas[i + 1].x) / 2;
      d = (this.Montanhas[i].y + this.Montanhas[i + 1].y) / 2;
      janela.quadraticCurveTo(this.Montanhas[i].x, this.Montanhas[i].y, c, d);
    }window.CP.exitedLoop(1);
    janela.lineTo(janela.width - this.x, janela.height);
    janela.lineTo(0 - this.x, janela.height);
    janela.closePath();
    janela.fillStyle = this.color;
    janela.fill();
    return janela.restore();
  };

  // SETUP

  janela.setup = function () {
    var i, results;
    i = 5;
    results = [];
    while (i--) {if (window.CP.shouldStopExecution(2)) break;
      results.push(MontanhaRanges.push(new MontanhaRange({
        layer: i + 1,
        width: {
          min: (i + 1) * 50,
          max: (i + 1) * 70 },

        height: {
          min: 200 - i * 40,
          max: 300 - i * 40 },

        speed: (i + 1) * .003,
        color: 'hsl(' + p + ', ' + ((i + 1) * 1 + 10) + '%, ' + (75 - i * 13) + '% )' })));
      console.log("Hello world!");

    }window.CP.exitedLoop(2);
    return results;
  };

  // CLEAR

  janela.clear = function () {
    return janela.clearRect(0, 0, janela.width, janela.height);
  };

  // UPDATE

  janela.update = function () {
    var i, results;
    dt = janela.dt < .1 ? .1 : janela.dt / 16;
    dt = dt > 5 ? 5 : dt;
    i = MontanhaRanges.length;
    results = [];
    while (i--) {if (window.CP.shouldStopExecution(3)) break;
      results.push(MontanhaRanges[i].update(i));
    }window.CP.exitedLoop(3);
    return results;
  };

  // DRAW

  janela.draw = function () {
    var i, results;
    i = MontanhaRanges.length;
    results = [];
    while (i--) {if (window.CP.shouldStopExecution(4)) break;
      results.push(MontanhaRanges[i].render(i));
    }window.CP.exitedLoop(4);
    return results;
  };

  // Mousemove Fix

  $(window).on('mousemove', function (e) {
    janela.mouse.x = e.pageX;
    return janela.mouse.y = e.pageY;
  });

}).call(this);

and where I define the color is in the variable p:

color: 'hsl(' + p + ', ' + ((i + 1) * 1 + 10) + '%, ' + (75 - i * 13) + '% )' })));

that I start with 120 because it’s green:

Cores

As I can choose and change the following color, I’m using this code but it doesn’t work because it re-loads the page and reloads the green 120:

    $(document).ready(function() {
    var user = "none";
    $(".user").click(function() {
        user = $(this).attr("data-name");
    });
        $("#test").click(function() {
        window.location.reload();
        p = 240
    });
});

https://wetransfer.com/downloads/9750925d9751abeb292977194665014e20190723191111/94cc2ddd87a539708982e527128a207c20190723191111/c790f0

  • 1

    I think you’re complicating something you could do with just CSS.... Put in your question a full example, or at least a link where to test the template. The way it is is complicated to answer you, until pq can not know if the image is a canvas, svg, or png for example....

  • Thanks for the repair, I’ve put the full JS code,

2 answers

15

Follow here a basic example only with CSS, the principle is p, because it uses the filter: hue-matrix to control the color histogram of the image. And as the filter() accepted transition you achieve a smooth transition between colors.

inserir a descrição da imagem aqui

The idea is to have a group of radio-buttons hidden with their respective labels that are the btns visible from the screen. When you click on this label you activate the radio-btn corresponding and using the adjacent selector ~ you change the heart of the image below, but in the same hierarchy...

To better understand follows the code, it can be even more optimized, but I left well simplão even for you better understand what was done.

.container {
    text-align: center;
}
.box {
    width: 400px;
    height: 260px;
    background-image: url(https://banner2.kisspng.com/20180625/khb/kisspng-mountain-cartoon-clip-art-snow-mountain-5b31b86c4dd650.2273242715299851323188.jpg);
    background-size: cover;
    margin: 20px auto;
    filter: none;
    transition: filter 500ms linear;
}
label {
    padding: 10px;
    border: 1px solid #000;
    cursor: pointer;
}
[for="green"] {
    background-color: green;
}
[for="blue"] {
    background-color: blue;
}
[for="red"] {
    background-color: red;
}
#green:checked ~ [for="green"] {
    background-color: black;
    color: #ffffff;
}
#blue:checked ~ [for="blue"] {
    background-color: black;
    color: #ffffff;
}
#red:checked ~ [for="red"] {
    background-color: black;
    color: #ffffff;
}
#green:checked ~ .box {
    filter: hue-rotate(70deg);
}
#blue:checked ~ .box {
    filter: hue-rotate(150deg);
}
#red:checked ~ .box {
    filter: hue-rotate(230deg);
}
#nada:checked ~ .box {
    filter: none;
}

[name="cores"] {
    display: none;
}
<div class="container">
    <input type="radio" name="cores" id="green">
    <input type="radio" name="cores" id="blue">
    <input type="radio" name="cores" id="red">
    <input type="radio" name="cores" id="nada">
    <label for="green">green</label>
    <label for="blue">blue</label>
    <label for="red">red</label>
    <label for="nada">nada</label>
    <div class="box"></div>
</div>


Hint, putting the image in one color only.

inserir a descrição da imagem aqui

If you want to leave the image as above you need to follow a few steps, there are other ways to do this using [blend-mode][3] etc, but as we are already using filter I’ll keep it that way.

First keep in mind that we may have more than one filter inside the filter. Then I’ll put a filter to leave the image on black & white using grayscale(100%), then I put the filter sepia(100%) to give a homogeneous yellowish tone in the image, I need that color so I can use the hue-rotate(XXXdeg) and set the predominant color of the image.

Follow the simple code, just applying this technique in the image to get more didactic...

body {display:flex}
.filtro-green {
    filter: grayscale(100%) sepia(100% ) hue-rotate(70deg);
}
.box {
    width: 400px;
    height: 260px;
    background-image: url(https://banner2.kisspng.com/20180625/khb/kisspng-mountain-cartoon-clip-art-snow-mountain-5b31b86c4dd650.2273242715299851323188.jpg);
    background-size: cover;
    margin: 20px auto;
    transition: filter 500ms linear;
}
com filtros
<div class="box filtro-green"></div>
sem filtros
<div class="box"></div>

  • Hello, first of all thank you very much for your reply but what I want is not to change the background color but to change a variable that defines the landscape color. Here’s what I have for now, I can’t put all the code here but just run the html to understand what I want, https://www.dropbox.com/s/7xq45vq2ox3tms7/Resolucao.rar?dl=0

  • @Sapires I could not download the Dropbox, however I left there a new answer, now with the function done with JS, and changing the values according to the date-attribute used in the button. Take a look at the other answer, I think it’s closer than you needed.

7

First I am adding this second answer, because the previous answer has already been very long, and I treated only one solution with CSS, but the author of the question seems to really need an answer in Javacript

Not to mix the subjects I will make this other answer focusing only on JS, and leaving the other answer only with CSS for consultation, because I think it is of interest to the community.

Get to the points.

The idea is to use a attribute date, who I called datar-cor and is present in every button to change the value of a CSS variable that will be in the :root. So when you click on btn, activates a function that picks up the data-cor of the attribute and boot as a value of hue-rotate() of a variable that is in CSS.

The first step is to create a variable in the :root CSS to put the hue-rotate(XXXdeg), I called this variable --cor. And we’ll exchange her value by identifying the data-cor of button clicked and replacing the value of this --cor in css.

In the forEach click on btn i tb added in function to make a addClass .active on the button clicked, this is only to give feedback to the user, but if you do not want to just withdraw...

inserir a descrição da imagem aqui

The other information about the color transition is in the previous answers if you are interested...

To better understand I left the comments in the code.

const btn = document.querySelectorAll("button");
const root = document.documentElement;

function mudaCor(bt) {
  //pega o valor do data-cor do botão clicado e coloca como valor da variável --cor no :root;
  btn.forEach((datac) => {
    datac = this.getAttribute('data-cor');
    root.style.setProperty('--cor', datac );
  });

  //coloca classe ativo no btn clicado e remove dos irmãos
  btn.forEach( (limpa) => {
    limpa.classList.remove('ativo');
  })
  bt.currentTarget.classList.add('ativo');
}

// função que ativa quando o btn é clicado
btn.forEach((trocar) => {
  trocar.addEventListener('click', mudaCor);
});
:root {
  /* variável de cor que recebe o valor do data-cor do btn clicado */
  --cor: hue-rotate(0deg);
}

.container {
  text-align: center;
}

.box {
  width: 400px;
  height: 260px;
  background-image: url(https://banner2.kisspng.com/20180625/khb/kisspng-mountain-cartoon-clip-art-snow-mountain-5b31b86c4dd650.2273242715299851323188.jpg);
  background-size: cover;
  margin: 20px auto;
  filter: var(--cor);
  transition: filter 500ms linear;
}
button.ativo {
  background-color: black;
  color: #fff;
}
<div class="container">
  
  <!-- btns com o data-cor = o valor que vou substituir como valor do --cor no css -->
  <button data-cor="hue-rotate(70deg)">green</button>
  <button data-cor="hue-rotate(170deg)">blue</button>
  <button data-cor="hue-rotate(270deg)">red</button>
  <button class="ativo" data-cor="hue-rotate(0deg)">none</button>

  <div class="box" data-type="uma div"></div>
</div>

  • Thanks for the lost time, I tried to adapt your code in mine but it wasn’t, maybe because I don’t use a fixed image but a generated mountain is the problem, I put the project in: https://wetransfer.com/downloads/9750925d9751abeb292977194665014e20190723191111/94cc2ddd87a539708982e527128a207c20190723191111/c790f0

  • My problem is I’m using Parallax

  • @Sapires the problem is not the Parallax to my truth, the problem is how you build this parallels with JS, and at what moment you will set the properties in the element you want. Looks like it’s a canvas you’re gonna put together. Try to create an environment of this and will mounted all in parts, start with a single element and without Parallax and try to change the color by clicking on btn, and then vc will "completing" the script until you get to the point you want

  • But that’s exactly what I did, and I can get to the point of your project, but I put the mountain generation part and only the mountains appear in the color defined by the variable. I could see the code. Sorry and thank you

  • @Did Sapires solve it? Sometimes you need to put the function of changing the color inside a Settimeout, so the script will draw the mountains, and only after they "exist" you perform the function of changing the color something like this...

  • The mountains are being formed over the pages, it’s not just once, it’s Random constantly formed, I think that’s why the problem is

  • I don’t know much about JS, but what you can do is "save" the color you applied to the first mountain and the next one that comes up you apply this color. I know talking is easy, but with this part I can’t help you, my knowledge is limited in this area yet :/

  • no, I’m trying everything but I’ll have to research another way to do it, it’s really hard.

  • Try to get the project running on a Codepen or Jsfiddle, so it’s easier for us to see the real situation, or even on a Gitpage. It may be that picking somehow by the scroll event you create the next blanket with the color of the previous one. Even pq with CSS Currentcolor you can take a "base" color and pass as background, type background-color: currentColor Read more here that can help you: https://answall.com/questions/322824/o-que%C3%A9-e-como-use-the-attribute-currentcolor-no-css

  • I can’t get it running online because I have several . css , but just run html from here. https://wetransfer.com/downloads/9750925d9751abeb292977194665014e20190723191111/94cc2ddd87a539708982e527128a207c20190723191111/c790f0

Show 5 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.