Getting sliders to update HTML canvas - javascript

I'm trying to make a colour selector in JavaScript, so far it works (in Firefox, not chrome) if you select a value in the slider and then refresh the page - displaying the colour in a HTML tag.
However, I want it to refresh the colour real-time, so that the canvas changes colour as you adjust the sliders. I imagine I've made a really simple error, but I just can't figure it out - I would very much appreciate any help/advice!
Example of code on my web page.
I've messed around with using .onchange etc, plus declaring "outputR.value" in the rbg() call, but none of this works. I imagine I need an update function - but I'm not sure where to even start on that.
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
sliderR.oninput = function() {
outputR.innerHTML = this.value;
}
sliderG.oninput = function() {
outputG.innerHTML = this.value;
}
sliderB.oninput = function() {
outputB.innerHTML = this.value;
}
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb("+sliderR.value+","+sliderG.value+","+sliderB.value+")";
ctx.fillRect(0, 0, 80, 80);
<p>
<div class="slidecontainer">
<p>Red: <span id="demoR"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeR">
<p>Green: <span id="demoG"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeG">
<p>Blue: <span id="demoB"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeB">
<canvas id="myCanvas"></canvas>
</div>
</p>
<script src="js/canvastest.js"></script>
Expected: HTML canvas element changes colour when sliders are moved.
Actual: Colours only change when page is refreshed (in Firefox), or not at all (chrome).

I'm not seeing a point in which you update the canvas itself. You would want to update the canvas when the value changes such as:
ctx.fillStyle = "rgb(" + [outputR, outputG, outputB].join(', ') + ")";
then rerender with ctx.fillRect(0, 0, 80, 80);.
This would give you something like the following:
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
sliderR.oninput = function() {
outputR.innerHTML = this.value;
updateRect();
}
sliderG.oninput = function() {
outputG.innerHTML = this.value;
updateRect();
}
sliderB.oninput = function() {
outputB.innerHTML = this.value;
updateRect();
}
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
function updateRect() {
ctx.fillStyle = "rgb(" + [outputR, outputG, outputB].map(i => i.innerHTML).join(', ') + ")";
ctx.fillRect(0, 0, 80, 80);
}
updateRect();
st.js

First things first, you should not enclose your div or another p inside <p> tag. It's wrong structurally.
Now coming to your question, it is not re-rendering as the script is only getting executed on page load.
Try something like this:
var sliderR = document.getElementById("myRangeR");
var sliderG = document.getElementById("myRangeG");
var sliderB = document.getElementById("myRangeB");
var outputR = document.getElementById("demoR");
var outputG = document.getElementById("demoG");
var outputB = document.getElementById("demoB");
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
myfunc = () => {
outputR.innerHTML = sliderR.value;
outputG.innerHTML = sliderG.value;
outputB.innerHTML = sliderB.value;
ctx.fillStyle = "rgb("+sliderR.value+","+sliderG.value+","+sliderB.value+")";
ctx.fillRect(0, 0, 80, 80);
}
myfunc(); // for initialising values on first load
<div>
<div class="slidecontainer">
<p>Red: <span id="demoR"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeR" oninput="myfunc()" >
<p>Green: <span id="demoG"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeG" oninput="myfunc()">
<p>Blue: <span id="demoB"></span>/255</p>
<input type="range" min="0" max="255" value="128" class="slider" id="myRangeB" oninput="myfunc()">
<canvas id="myCanvas"></canvas>
</div>
</div>
Hope it helps!

Related

Type Error: How do I get a method to execute like a function in Javascript?

I was trying to create a Javascript function in HTML,which should create a rectangle and set the size to the likings of the user with this code:
class Rectangle{
constructor(height, width){
this.height = height;
this.width = width;
function createRectangle(Rectangle){
var input1 = document.getElementbyId("1stinput").value;
var input2 = document.getElementbyId("#2ndinput").value;
var input1int = parseFloat(input1);
var input2int = parseFloat(input2);
var Rectangle1 = new Rectangle(this.height=input1int, this.width=input2int);};
document.querySelector("Rectangle").setAttribute('width', parseFloat(Rectangle1.width));
document.querySelector("Rectangle").setAttribute('height', parseFloat(Rectangle1.height));
};
};
</script>
<input type="text" name="" value="" id="1stinput">
<input type="text" name="" value="" id="2ndinput">
<button onclick=Rectangle.createRectangle(Rectangle)>create</button>
<svg width=0 height=0>
<rect width=0 height=0 style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" id="Rectangle"/>
</svg>
But that didn't work,I got this Error:
Uncaught TypeError: Rectangle.createRectangle is not a function
at HTMLButtonElement.onclick
So I think,that createRectangle shoud be a method,but I don't know how to implement methods in the button,can someone Please help me?
That would be very nice,thank you!!!
You may want to revisit how you're approaching this. Classes have methods so you can't just add a function to them (here's the documentation). Additionally, maybe keep DOM manipulations out the class itself, and just let that return an HTML string based on the input values. You can then add that to a DOM element of your choosing.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
createRectangle() {
return `
<svg>
<rect width="${this.width}px" height="${this.height}px"></rect>
</svg>
`;
}
}
const input1 = document.querySelector('#input1');
const input2 = document.querySelector('#input2');
const button = document.querySelector('button');
const output = document.querySelector('#output');
button.addEventListener('click', handleClick, false);
function handleClick() {
const n1 = parseFloat(input1.value);
const n2 = parseFloat(input2.value);
const rectangle = new Rectangle(n1, n2);
output.innerHTML = rectangle.createRectangle();
}
svg { width: 100%; }
rect { fill: rgb(0, 0, 255); stroke-width: 3; stroke: rgb(0, 0, 0);}
#output { margin-top: 1em; }
<input type="text" id="input1">
<input type="text" id="input2">
<button>create</button>
<div id="output"></div>
Additional documentation
querySelector
Template/string literals

Unable to copy canvas element

I have a HTML page where an image is uploaded, the uploaded image is redrawn on a canvas element then converted to base64.
The first element works as expected but when I try to duplicate the code it doesn't work for the second code.
The code I have is:
<article>
<h3>Image 1</h3>
<p></p>
<li id="li_42" >
<div>
<input id="element_42" name="element_42" class="element file" type="file"/>
<br/>canvas:<br/>
<canvas id="canvas" width=64 height=64></canvas>
<textarea id="element_42_a" rows="5" ></textarea>
<script>
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var maxW=64;
var maxH=64;
var input = document.getElementById('element_42');
var output = document.getElementById('element_42_a');
input.addEventListener('change', handleFiles);
function handleFiles(e) {
var img = new Image;
img.onload = function() {
var iw=img.width;
var ih=img.height;
var scale=Math.min((maxW/iw),(maxH/ih));
var iwScaled=iw*scale;
var ihScaled=ih*scale;
canvas.width=iwScaled;
canvas.height=ihScaled;
ctx.drawImage(img,0,0,iwScaled,ihScaled);
output.value = canvas.toDataURL("image/jpeg",0.5);
}
img.src = URL.createObjectURL(e.target.files[0]);
}
</script>
</div>
<article>
<h3>Image 2</h3>
<li id="li_43" >
<div>
<input id="element_43" name="element_43" class="element file2" type="file"/>
<br/>canvas:<br/>
<canvas id="canvas2" name="canvas2" width=64 height=64></canvas>
<textarea id="element_43_a" rows="5"></textarea>
<script>
var canvas=document.getElementById("canvas2");
var ctx=canvas2.getContext("2d");
var cw=canvas2.width;
var ch=canvas2.height;
var maxW=64;
var maxH=64;
var input = document.getElementsByClassName("element file2");(
var output = document.getElementById('element_43_a');
input.addEventListener('change', handleFiles);
function handleFiles(e) {
var img = new Image;
img.onload = function() {
var iw=img.width;
var ih=img.height;
var scale=Math.min((maxW/iw),(maxH/ih));
var iwScaled=iw*scale;
var ihScaled=ih*scale;
canvas2.width=iwScaled;
canvas2.height=ihScaled;
ctx.drawImage(img,0,0,iwScaled,ihScaled);
output.value = canvas2.toDataURL("image/jpeg",0.5);
}
img.src = URL.createObjectURL(e.target.files[0]);
}
</script>
</div>
</body>
</html>
Can someone please point me in the right direction and advise what I need to do, so both sections work?
getElementsByClassName returns an array and not a single element. If you want to use it, you would need to rewrite your second input to something like document.getElementsByClassName("element file2")[0]. (Note the [0] at the end.)
Try to keep your code DRY. You should not repeat so many lines and rely more on functions instead.
function redrawOnCanvas(myCanvas, myInput, myOutput) {
var canvas = document.getElementById(myCanvas);
var ctx = canvas.getContext("2d");
var maxW = 64;
var maxH = 64;
function handleFiles(e) {
var img = new Image;
img.onload = function() {
var iw = img.width;
var ih = img.height;
var scale = Math.min((maxW / iw), (maxH / ih));
var iwScaled = iw * scale;
var ihScaled = ih * scale;
canvas.width = iwScaled;
canvas.height = ihScaled;
ctx.drawImage(img, 0, 0, iwScaled, ihScaled);
output.value = canvas.toDataURL("image/jpeg", 0.5);
}
img.src = URL.createObjectURL(e.target.files[0]);
}
var input = document.getElementById(myInput);
var output = document.getElementById(myOutput);
input.addEventListener('change', handleFiles);
}
redrawOnCanvas('canvas', 'element_42', 'element_42_a');
redrawOnCanvas('canvas2', 'element_43', 'element_43_a');
<article>
<h3>Image 1</h3>
<li id="li_42">
<div>
<input id="element_42" name="element_42" class="element file" type="file" />
<br/>canvas:<br/>
<canvas id="canvas" width=64 height=64></canvas>
<textarea id="element_42_a" rows="5"></textarea>
</div>
</li>
</article>
<article>
<h3>Image 2</h3>
<li id="li_43">
<div>
<input id="element_43" name="element_43" class="element file2" type="file" />
<br/>canvas:<br/>
<canvas id="canvas2" name="canvas2" width=64 height=64></canvas>
<textarea id="element_43_a" rows="5"></textarea>
</div>
</li>
</article>

Fabricjs filter

i made the code,but I always get this error "TypeError: (intermediate value)(intermediate value).filter is not a function
at i.applyFilters "
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg', function(img) {
var oImg = img.set({
left: 50,
top: 50
});
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
}, {
crossOrigin: 'anonymous'
});
function applyFilter(index, filter) {
var obj = canvas.getActiveObject();
obj.filters[index] = filter;
obj.applyFilters(canvas.renderAll.bind(canvas));
}
var f = fabric.Image.filters;
document.getElementById("input").onchange = function() {
applyFilter(0, new f.Contrast({
contrast: parseInt(document.getElementById("input").value, 10)
}));
};
<canvas width=600 height=400 id="c"></canvas>
<input id="input" type="range" min="-255" max="255" value="0" />
thank you for the answer,but this does not work.the image is only changed to one color
Change this line:
obj.applyFilters(canvas.renderAll.bind(canvas));
To
obj.applyFilters();
canvas.renderAll();
Also, the Contrast filter only accepts values between -1 and 1 (see http://fabricjs.com/docs/fabric.Image.filters.Contrast.html), so change this line:
<input id="input" type="range" min="-255" max="255" value="0" />
To this:
<input id="input" type="range" min="-100" max="100" value="0" />
And then divide the value from the input by 100
parseInt(document.getElementById("input").value, 10) / 100
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg', function(img) {
var oImg = img.set({
left: 50,
top: 50
});
canvas.add(oImg).renderAll();
canvas.setActiveObject(oImg);
}, {
crossOrigin: 'anonymous'
});
function applyFilter(index, filter) {
var obj = canvas.getActiveObject();
obj.filters[index] = filter;
obj.applyFilters();
canvas.renderAll();
}
var f = fabric.Image.filters;
document.getElementById("input").onchange = function() {
applyFilter(0, new f.Contrast({
contrast: parseInt(document.getElementById("input").value, 10) / 100
}));
};
<script src="https://unpkg.com/fabric#4.4.0/dist/fabric.js"></script>
<canvas width=600 height=400 id="c"></canvas>
<input id="input" type="range" min="-100" max="100" value="0" />

JQuery for loop, for vectors

I am trying to make a vector calculator to practice my jquery skills and I have an Issue. I have a .option div where I have fields for the force and the angle. If I click the #calc_v button another field is inserted.
<div class="option">
<h2>Vectors</h2>
<a class="close">Close X</a><br/>
<div id="move">1.<input type="number" step="0.01" id="N1"/> Newtons(or meters) à <input type="number" step="0.01" id="A1"/> Degrees
<br/></div>
<button id="calc_v">Calculer</button>
<a id="add_move">+ VECTOR</a>
<div id="log_v"></div>
here is my jquery code:
<script>
//vectors
var vector = 1;
$("#add_move").click(function () {
vector++;
$("#move").append(vector+".<input type='number' step='0.01' id='N"+vector+"'/> Newtons(ou mètres) à <input type='number' step='0.01' id='A"+vector+"'/> Degrées<br/>");
});
$("#calc_v").click(function(){
var x_v = 0;
var y_v = 0;
var ite = 0;
for(x=1; x <= vector; x++){
//for each added vector give it a var name
ite++;
var f = "#N"+ite;
var a = "#A"+ite;
//then, find its value
var force = $(f).val();
var f_val = parseFloat(force);
var angle = $(a).val();
var a_val = parseFloat(angle);
//analyse it
var cons_x = ((f_val)*(Math.cos(a_val))) * (180 / Math.PI);
var cons_y = ((f_val)*(Math.sin(a_val))) * (180 / Math.PI);
//add it to each x,y coords
x_v += cons_x;
y_v += cons_y;
}
$("#log_v").html("Coords: ("+ x_v + ","+ y_v + ") |f"+force +"|a"+ angle +"|i"+ ite+"|v"+vector);
});

Unexpected result with range input values

This problem is (probably) not caused by the width/height being in the CSS, because it isn't. (How to avoid HTML Canvas auto-stretching)
When trying to make rage inputs to demonstrate an issue I was having, I found that when using range inputs it acted stranger. It seems to be representing a larger number than what I'm passing in.
Please check my code out and tell me what's causing all this. http://codepen.io/Magnesium/pen/wMwwgx
var engine = function(canvas) { // Trying to make a game engine when the problems started
this.canvas = canvas.getContext("2d");
this.defaultColor = "#FF0000";
this.clearCanvas = function() { // Clears canvas
this.canvas.clearRect(0, 0, canvas.width, canvas.height);
};
this.square = function(x, y, size, color) { // Makes a square. I don't see any problems, but if the error is caused by me it would probably be here
if (color == undefined) color = this.defaultColor;
this.canvas.fillStyle = color;
this.canvas.fillRect(x, y, x + size, y + size);
};
}
var canvas = document.getElementById("canvas");
var rangeX = document.getElementById("x");
var rangeY = document.getElementById("y");
var size = document.getElementById("sz");
var outX = document.getElementById("ox");
var outY = document.getElementById("oy");
var outSize = document.getElementById("osz");
var out = document.getElementById("out");
var enjin = new engine(canvas); // New engine
var defalt = false;
var src = document.getElementById("src");
setInterval(function() { // Called ~30 times a second
enjin.clearCanvas();
defalt ? enjin.square(50, 50, 50) : enjin.square(rangeX.value, rangeY.value, size.value);
defalt ? out.innerHTML = "enjin.square(50, 50, 50);" : out.innerHTML = "enjin.square("+rangeX.value+", "+rangeY.value+", "+size.value+");";
defalt ? src.innerHTML = "Using in-code values" : src.innerHTML = "Using slider values";
outX.innerHTML = rangeX.value;
outY.innerHTML = rangeY.value;
outSize.innerHTML = size.value;
}, 30);
The values you're passing to enjin.square are strings. You need to parse them to int:
enjin.square(parseInt(rangeX.value), parseInt(rangeY.value), parseInt(size.value));
Here's a working example:
var engine = function(canvas) { // Trying to make a game engine when the problems started
this.canvas = canvas.getContext("2d");
this.defaultColor = "#FF0000";
this.clearCanvas = function() { // Clears canvas
this.canvas.clearRect(0, 0, canvas.width, canvas.height);
};
this.square = function(x, y, size, color) { // Makes a square. I don't see any problems, but if the error is caused by me it would probably be here
if (color == undefined) color = this.defaultColor;
this.canvas.fillStyle = color;
this.canvas.fillRect(x, y, x + size, y + size);
};
}
var canvas = document.getElementById("canvas");
var rangeX = document.getElementById("x");
var rangeY = document.getElementById("y");
var size = document.getElementById("sz");
var outX = document.getElementById("ox");
var outY = document.getElementById("oy");
var outSize = document.getElementById("osz");
var out = document.getElementById("out");
var enjin = new engine(canvas); // New engine
var defalt = false;
var src = document.getElementById("src");
setInterval(function() { // Called ~30 times a second
enjin.clearCanvas();
defalt ? enjin.square(50, 50, 50) : enjin.square(parseInt(rangeX.value), parseInt(rangeY.value), parseInt(size.value));
defalt ? out.innerHTML = "enjin.square(50, 50, 50);" : out.innerHTML = "enjin.square(" + rangeX.value + ", " + rangeY.value + ", " + size.value + ");";
defalt ? src.innerHTML = "Using in-code values" : src.innerHTML = "Using slider values";
outX.innerHTML = rangeX.value;
outY.innerHTML = rangeY.value;
outSize.innerHTML = size.value;
}, 30);
#canvas {
border: 1px solid black;
}
<canvas id='canvas' width='400' height='400'></canvas>
<br />X
<input type='range' id='x' /><span id='ox'></span>
<br />Y
<input type='range' id='y' /><span id='oy'></span>
<br />Size
<input type='range' id='sz' /><span id='osz'></span>
<br /><span id='out'></span>
<br />
<button onclick='defalt = !defalt;'>Default value toggle</button>
<span id='src'></span>
And a updated pen.

Categories