I'm new to coding and just created a Pixel Art Maker!
I am experimenting with jQuery and am wanting to know if:
• there is a proper event method that I can call to create an effect for:
"If I click and drag my mouse over certain cells, the colors of the cells will change."
Currently I have my table set up to where you click it once, it adds color, if you click it a second time, it removes the color.
I would like a user to just drag their mouse to give it the effect like they are drawing.
I tried implementing using mouseDown() and select() but that didnt work.
Any help on how I can implement this would be appreciated. Even better if you don't give me the exact answer right off the bat, but give me hints on what jQuery event methods and listeners I should be using and where I would put it in the code so that way I can learn.
Thanks all!
Codepen Demo: https://codepen.io/chaycesol/full/Qmmyjq
var height, width, color;
// When size is submitted by the user, call makeGrid()
$('#sizePicker').submit(function (event) {
event.preventDefault();
height = $('#inputHeight').val();
width = $('#inputWeight').val();
makeGrid(height, width);
});
function makeGrid(h,w) {
//Removes grid if one is already present before pressing submit
$('tr').remove();
// Creating each table row
for (var i= 1; i <= h; i++) {
$('#pixelCanvas').append('<tr id=table' + i + '></tr>');
for (var j = 1; j <=w; j++) {
$('#table' + i).append('<td></td>');
}
}
//Draw with color in table cells
$('td').click(function addColor() {
color = $('#colorPicker').val();
if ($(this).attr('style')) {
$(this).removeAttr('style')
} else {
$(this).attr('style', 'background-color:' + color);
}
});
Related
I am making a task to recreate paint kind of by making 100 x 50 cells and onlcick giving them a background color that is selected. But to make the drawing easier a user should be able to hold his mouse button and drag over the cells to make them fill in with a background color. As soon as he releases the mouse button the drawing should stop and you are back to clicking or have to hold the mouse button again.
I have tried to do this with a .mousemove but that did not work out.
// MAKING THE GRID
for (let i = 1; i <= 49; i++){
$('#canvas').append('<tr id="table' + i + '"</tr>');
for(let j = 1; j <= 100; j++){
$('#table' + i).append('<td></td>');
}
}
// ADDING A COLOR ON CLICK
$('td').click(function kleur(){
if($(this).attr('style')){
$(this).removeAttr('style')
} else {
$(this).attr('style', 'background-color:' + color);
}
})
// SELECTING COLOR ON RIGHT CLICK
$('td').mousedown(function(e) {
switch (event.which) {
case 3:
$('.popup').show();
$('.popup').css({left: e.pageX});
$('.popup').css({top: e.pageY});
}
});
Try listen to mouseover event and check if the button was pressed. It would look somehow like:
$("#canvas").on("mouseover", function(e) {
if(e.buttons == 1)
Draw(e.target);
});
I made quick example for you (in vanilla JS unfortunately, I dont use jQuery anymore):
https://codepen.io/DooMxDD/pen/RmWqjM
It worked out by adding these lines of code.
// Adding the selected color to coloring function
function kleur(target) {
target.style.backgroundColor = color;
}
// Coloring when mouse is held down
$("#canvas").on("mouseover", function(e) {
if(e.buttons == 1)
kleur(e.target);
});
The program currently runs with no errors in dev tools. Everything is performing besides the last part of code. After I enter the input in the prompt the container clears but will not let me draw inside of it with the newly set variables?
var row=16;
var sizeofsquare=45;
function gridLife() {
for (var x = 0; x < row; x++){
for (var y = 0; y < row; y++){
$("<div class='square'></div>").appendTo(".container");
}
}
}
$(document).ready(function(){
gridLife();
$('.square').on('mouseenter', function() {
$(this).css('background-color', 'black');
});
});
$(document).ready(function(){
$('.buttons').click(function(){
$('.container').empty();
row = prompt ('How many sqaures would you like?');
sizeofsquare = 720/row;
});
});
The problem is you're removing all the squares by calling $('.container').empty(), but not putting them back afterwards. At the end of your button click handler, you should call gridLife() again to regenerate the grid elements.
However, it will still not work because only the original square elements had the mouseenter events bound. The new squares won't have that event handler anymore. You could fix this by calling $('.square').on again, but that's messy. The best way is to use the optional selector argument to .on(), like this:
$('.container').on('mouseenter', '.square', function () {
$(this).css('background-color', 'black');
});
Now, all .square elements that ever exist within the .container element will automatically trigger that same event.
I've created a script that attaches an event listener to a collection of pictures by default. When the elements are clicked, the listener swaps out for another event that changes the image source and pushes the id of the element to an array, and that reverses if you click on the swapped image (the source changes back and the last element in the array is removed). There is a button to "clear" all of the images by setting the default source and resetting the event listener, but it doesn't fire reliably and sometimes fires with a delay, causing only the last element in a series to be collected.
TL;DR: An event fires very unreliably for no discernible reason, and I'd love to know why this is happening and how I should fix it. The JSFiddle and published version are available below.
I've uploaded the current version here, and you can trip the error by selecting multiple tables, pressing "Cancel", and selecting those buttons again. Normally the error starts on the second or third pass.
I've also got a fiddle.
The layout will be a bit wacky on desktops and laptops since it was designed for phone screens, but you'll be able to see the issue and inspect the code so that shouldn't be a problem.
Code blocks:
Unset all the selected tables:
function tableClear() {
//alert(document.getElementsByClassName('eatPlace')[tableResEnum].src);
//numResTables = document.getElementsByClassName('eatPlace').src.length;
tableArrayLength = tableArray.length - 1;
for (tableResEnum = 0; tableResEnum <= tableArrayLength; tableResEnum += 1) {
tableSrces = tableArray[tableResEnum].src;
//alert(tableSrcTapped);
if (tableSrces === tableSrcTapped) {
tableArray[tableResEnum].removeEventListener('click', tableUntap);
tableArray[tableResEnum].addEventListener('click', tableTap);
tableArray[tableResEnum].src = window.location + 'resources/tableBase.svg';
} /*else if () {
}*/
}
resTableArray.splice(0, resTableArray.length);
}
Set/Unset a particular table:
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'resources/tableBase.svg');
resTableArray.shift(this);
};
tableTap = function () {
$(this).unbind('click', tableTap);
$(this).bind('click', tableUntap);
this.setAttribute('src', 'resources/tableTapped.svg');
resTableArray.push($(this).attr('id'));
};
Convert the elements within the 'eatPlace' class to an array:
$('.eatPlace').bind('click', tableTap);
tableList = document.getElementsByClassName('eatPlace');
tableArray = Array.prototype.slice.call(tableList);
Table instantiation:
for (tableEnum = 1; tableEnum <= tableNum; tableEnum += 1) {
tableImg = document.createElement('IMG');
tableImg.setAttribute('src', 'resources/tableBase.svg');
tableImg.setAttribute('id', 'table' + tableEnum);
tableImg.setAttribute('class', 'eatPlace');
tableImg.setAttribute('width', '15%');
tableImg.setAttribute('height', '15%');
$('#tableBox').append(tableImg, tableEnum);
if (tableEnum % 4 === 0) {
$('#tableBox').append("\n");
}
if (tableEnum === tableNum) {
$('#tableBox').append("<div id='subbles' class='ajaxButton'>Next</div>");
$('#tableBox').append("<div id='cazzles' class='ajaxButton'>Cancel</div>");
}
}
First mistake is in tapping and untapping tables.
When you push a Table to your array, your pushing its ID.
resTableArray.push($(this).attr('id'));
It will add id's of elements, depending on the order of user clicking the tables.
While untapping its always removing the first table.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
resTableArray.shift(this);
So, when user clicks tables 1, 2, 3. And unclicks 3, the shift will remove table 1.
Lets fix this by removing untapped table
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'http://imgur.com/a7J8OJ5.png');
var elementID = $(this).attr('id');
var elementIndex = resTableArray.indexOf(elementID);
resTableArray.splice(elementIndex, 1);
};
So you were missing some tables after untapping.
Well lets fix tableClear,
You have a array with tapped tables, but you are searching in main array.
function tableClear() {
tableLen = resTableArray.length;
for (var i = 0; i < tableLen; i++) {
var idString = "#" + resTableArray[i];
var $element = $(idString);
$element.unbind('click', tableUntap);
$element.bind('click', tableTap);
$element.attr("src", 'http://imgur.com/a7J8OJ5.png');
}
resTableArray = [];
}
Im searching only tapped tables, and then just untap them and remove handlers.
fiddle: http://jsfiddle.net/r9ewnxzs/
Your mistake was to wrongly remove at untapping elements.
The use case is that I have an html canvas on top of several html elements which listen for right click mouse events. I want to draw on the canvas using left mouse button, and at the same time interact with underlying html elements using right click.
I get that I can allow all mouse events to pass through the canvas by setting css property pointer-events to none. However I want to allow only right click to pass through it.
One way to achieve this may be to listen on the canvas for right click, set pointer-events to none in the callback, manually fire a right click event again and set pointer-events back to auto.
Btw I'm using KineticsJS and I have no idea how to manually fire mouse events using it.
Any suggestions would be appreciated.
Interesting subject that caught my attention. It was fun to come up with a solution to it based on this jQuery approach and some others. I'm not familiar with KineticsJS, but this is a plain javascript approach
In essence you can fake a pointer-events:none for just the right click by using the object's dimensions/positioning and onmousedown's event.which to determine if a right click was clicked on the background elements. The following is an example of that approach, hopefully the comments explain it well
// Get all overlaying canvases
var canvas = document.getElementsByTagName("canvas"),
// Get all elements that you want the click to fire on
background = document.getElementsByClassName("background");
// Use click location and dimensions/positioning to fake a click through
function passThrough(e) {
// Allow only right click to pass through
if(e.which == 2 || e.which == 3) {
// Check all background elements
for(var i = 0; i < background.length; i++) {
// check if clicked point (taken from event) is inside element
var mouseX = e.pageX;
var mouseY = e.pageY;
var obj = background[i];
var width = obj.clientWidth;
var height = obj.clientHeight;
if (mouseX > obj.offsetLeft && mouseX < obj.offsetLeft + width
&& mouseY > obj.offsetTop && mouseY < obj.offsetTop + height) {
// Force click event if within dimensions
background[i].onclick();
}
}
}
}
for(var i = 0; i < canvas.length; i++) {
// Force our function when clicked
canvas[i].onmousedown = passThrough;
// Prevent menu from appearing
canvas[i].oncontextmenu = function(event) { event.returnDefault; return false; }
}
for(var i = 0; i < background.length; i++) {
// Toggle background when clicked (to show it works)
background[i].onclick = function() {
if(this.style.background == "black") {
this.style.background = "red";
}
else {
this.style.background = "black";
}
}
}
I hope it suits your needs!
I have a container with left pane and right pane. You can drag from left pane, and drop on right pane. For some reason, the html 5 ondragover event is not triggered if the drop target is already completely occupied. My drop target is a div, and I would be dynamically creating iframes in it when ondrop event occurs. I am able to create the 1st iframe when I drag something for the first time from left and drop it to left. But now for the 2nd time if I drag something from the left and try to drop it to right, the ondragover is not getting triggered(I put the breakpoint, its not getting hit), because the drop target is already full with my 1st iframe. In the ondragover listener I would like to reduce the height of existing iframe to half, so as to make room for creation of new iframe. But unfortunately the ondragover is just not getting triggered. Is there any way I can modify the behaviour of ondragover, so that it gets triggered even if the drop target is completely occupied? Any help would be greatly appreciated. So, here is the code ..
function onDragOver(ev) {
ev.preventDefault();
if(iframes_count > 4)
{
return;
}
if (iframes_count == 2)
{
if ((getDivLeftCoordinate() < ev.pageX < getDroppableWidth()) && (getDivTopCoordinate() < ev.pageY < getDroppableHeight()/2))
{
var existingFrames = document.getElementsByTagName("iframe");
for (var i = 0; i < existingFrames.length; i++)
{
$(this).attr("height" , 500);
}
}
}
$("#right_pane").css("background-color", "grey");
}
function onDrop(ev) {
ev.preventDefault();
var data_id = ev.dataTransfer.getData("Text");
var data_id_selector= "#" + data_id;
var content_id = data_id + "content";
var content_id_selector = "#" + content_id;
var url = $(data_id_selector).data("url");
var iframe_width = 100 + "%";
var iframe_height = 100 + "%";
$(data_id_selector).remove();
$("<iframe />", {
class: "myFrame",
id : content_id,
}).appendTo('#right_pane');
$(content_id_selector).attr("height", iframe_height);
$(content_id_selector).attr("width", iframe_width);
$(content_id_selector).attr("src", url);
$(content_id_selector).attr("background-color", "white");
$("#right_pane").css("background-color", "white");
}
perhaps just a syntax issue, the event in HTML5 is dragover (no on)
more html5 drag n drop info here:
http://www.w3.org/TR/2010/WD-html5-20101019/dnd.html
http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
http://www.html5rocks.com/en/tutorials/dnd/basics/
http://html5demos.com/drag