I am having a hard time figuring out how to create a drag and drop feature in my app that will accept a draggable item and decide whether it is the correct answer and if it is correct it will display a message saying success!
My app displays two images both images are portions of a pizza pie and then it will display 8 draggable numbers that you have to choose from and drag them into a droppable box which will check if its correct. So i start with ...
PizzaImageOne[1]="http://s23.postimg.org/6yojml8vb/Pizza_One.png"
PizzaImageOne[2]="http://s13.postimg.org/5d8zxnb2b/pizzatwo.png"
this happens 8 times so each number of the array represents how many slices it holds
then i call var whichImage = Math.round(Math.random()*(p-1)); i store a random # into the variable whichImage which holds the number of pizza slices because each array # correlates with the pizza slices image which i will use to generate random pizzas by doing this
document.write('<img src="'+theImages[whichImage]+'">');
I do that all over again with a new array
PizzaImageTwo[1]="http://s23.postimg.org/6yojml8vb/Pizza_One.png"
PizzaImageTwo[2]="http://s13.postimg.org/5d8zxnb2b/pizzatwo.png"
same exact thing but with new variables so the random call can be different than the first one
var whichImage2 = Math.round(Math.random()*(p-1))
then i have
<script>
$(function() {
$( "#draggable1" ).draggable();
});
</script>
I do that 8 times so #draggable1, #draggable2, draggable3, ... all the way to 8
i then made an array and saved them into each array like this 8 times each draggable function represents numbers from 1 to 8 because we are adding pizza pies like fractions
<script>
var theimagestwo = new Array();
Draggablenumber[1] = $("#draggable1");
DraggableNumber[2] = $("#draggable2");
I do this until i fill up 8 draggable numbers in each array
So the logic is MyAnswer = WhichImage + WhichImage2 Then i have to check if DraggableNumber[MyAnswer] is dropped then i have the right answer...
How would i go about creating this feature??
Following your comment, this will be an easy task, you only need to follow these steps:
Create two random numbers contained in the slices array
Calculate the sum of these values
When you drop the number compare if this number is equal to the sum
of the slices
Here you have an example code:
HTML
<div id="slices">
</div>
<div id="options">
<div data-index="1">1</div>
<div data-index="2">2</div>
<div data-index="3">3</div>
<div data-index="4">4</div>
<div data-index="5">5</div>
<div data-index="6">6</div>
<div data-index="7">7</div>
<div data-index="8">8</div>
</div>
<div id="area">
drop area
</div>
jQuery UI
//---Vars
var slices = $("#slices");
var options = $("#options");
var area = $("#area");
var selected;
var result;
//---Array of images
var pizzas = [
{image: "http://s23.postimg.org/6yojml8vb/Pizza_One.png", value: 1},
{image: "http://s13.postimg.org/5d8zxnb2b/pizzatwo.png", value: 2},
{image: "http://s12.postimg.org/xfsxldqyx/pizzathree.png", value: 3},
{image: "http://s14.postimg.org/d6tdq0865/pizzafour.png", value: 4}
];
var total = pizzas.length;
//---Make boxes dragables
options.find("div").draggable();
//---When the boxes are dropped
area.droppable({
drop: function(event, ui){
if( Number( ui.draggable.attr("data-index") ) == result ){
alert("correct");
}else{
alert("incorrect");
}
}
});
//---Insert random pizza slices
function insertPizzas(){
selected = [];
result = 0;
//---Generate aleatory pieces
var rand
while(selected.length < 2){
//---Random value
rand = Math.floor( Math.random() * total );
//---Sum result
result += pizzas[rand].value;
selected.push( rand );
}
//---Clear the slices
slices.html("");
//---Add the new slices
selected.forEach(function(number){
var img = $("<img/>");
img.attr("src", pizzas[number].image);
slices.append(img);
});
}
insertPizzas();
jsfiddle
Related
I'm trying to write a google sheets script that would delete rows that have green background.
More detailed explanation:
I have a google sheets table in which:
first row represents the names of the columns (3)
all the following rows represent some 3-column data
What I need to do:
When any of the rows in the spreadsheet (except first one) is changed to have a green background, the setTimeout function should start, which would eventually delete all the data of the green row and set its background as white again.
What I've done so far:
I have a function that should return the hex value of the background color of the range:
function getHexValue(range) {
return SpreadsheetApp.getActiveSheet().getRange(range).getBackground();
}
I have a function that returns true if the input hex value is green:
function isGreen(color) {
return ["#b6d7a8", "#d9ead3", "#93c47d", "#6aa84f", "#38761d", "#274e13"].some(function(el) { return color === el; });
}
I've also tried to loop through the range and check for the background color in the following way:
var ss = SpreadsheetApp.getActiveSheet();
var range = ss.getRange('A2:C');
var numRows = range.getNumRows();
for (var i = 1; i < numRows; ++i) {
Logger.log(getHexValue(ss.getRange(i, 1)));
}
However, I keep getting the 'Invalid coordinates or range size' exceptions and, hence, cannot move forward. Besides, google prompts me that using getRange function in a loop is not a very good idea and can significantly slow down the script execution.
How do I approach my task in a correct way?
Here's how you can find green. Generally, I like to get all of the data at one time. That's why I use getDataRange() a lot. Once the data is in an array you can whip through it pretty quickly. The only trick is output. Remember, the data is in a 2D array. So if you're not using all of the array to setValues you may have to use the array itself to help you setup the right size range for the setValues() command.
function findGreenRow()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var cA=rg.getBackgrounds();
var gA=[];
var green='#00ff00'
for(var i=1;i<cA.length;i++)
{
if(cA[i][0] == green && cA[i][1] == green && cA[i][2]==green)
{
gA.push(sh.getRange(i+1,1,1,3).getA1Notation());
}
}
Logger.log(gA);
return gA
}
Here's a possible beginning to a more complete solution. It has a menu for the spreedsheet so you can run it from the spreadsheet and it displays the row ranges in a text area and it shows you how to use the withSuccessHandler for callbacks.
FindGreenRows.html
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
function findGreen()
{
google.script.run
.withSuccessHandler(dispGreenRanges)
.findGreenRows();
}
function dispGreenRanges(gA)
{
$('#txt1').val(gA.join(','));
}
</script>
</head>
<body>
<div id="div1">
<textarea id="txt1" rows="4" cols="35"></textarea>
<br /><input id="btn0" type="button" value="Find Green" title="Find green rows." onClick="findGreen();" />
</div>
</body>
</html>
Code.gs
function findGreenRows()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var cA=rg.getBackgrounds();
var gA=[];
var green='#00ff00';
for(var i=1;i<cA.length;i++)
{
if(cA[i][0] == green && cA[i][1] == green && cA[i][2]==green)
{
gA.push(sh.getRange(i+1,1,1,3).getA1Notation());
}
}
Logger.log(gA);
return gA
}
function showGreenDialog()
{
var ui=HtmlService.createHtmlOutputFromFile('FindGreenRows');
SpreadsheetApp.getUi().showModelessDialog(ui, 'Find Green');
}
function makeGreenMenu()
{
SpreadsheetApp.getUi().createMenu('The Green Menu')
.addItem('Find Green', 'showGreenDialog')
.addToUi();
}
Hope I can explain well.
So I have 8 boxes with class .boxA with a numeric value generated from js:
<div class="tfooter">
<div class="boxA" id="bx3" value="3">3</div>
<div class="boxA" id="bx27" value="27">27</div>
<div class="boxA" id="bx46" value="46">46</div>
<div class="boxA" id="bx40" value="40">40</div>
<div class="boxA" id="bx42" value="42">42</div>
<div class="boxA" id="bx29" value="29">29</div>
<div class="boxA" id="bx13" value="13">13</div>
<div class="boxA" id="bx1" value="1">1</div>
</div>
First of all I push all values in a array:
var randomnumber = Math.ceil(Math.random()*50);
var array = [];
$(".boxA").each(function(){
var dNumber = $(this).attr('value');
array.push(dNumber);
});
Each of this boxes contain a random number from 1 to 50.
Now, I want to generate another random number and check if exists in the array. If exists, generate another number until it's unique in that array. When is unique, create another div.
I've tryed with indexOf, with inArray, with while, but I can't get it working. The problem is that generate. Generate new number until not in array.
Thank you very much!
You could avoid the trial-and-error method by first building an array with the allowed values (i.e. those that do not appear in the list), and then pick a random value from that.
Here is a snippet that will add a new (non-used) number at the top of the list at the press of a button:
function getUsedNumbers() {
return $(".boxA").map(function(){
return +$(this).attr('value');
}).get();
}
function getCandidates(exclude) {
// Generate a list of values from 0 to 49, and make it a Set
// (Sets allow for faster look-up and value removal)
var candidates = new Set(Array(50).keys());
for (value of exclude) {
// Remove the already used value from our Set:
candidates.delete(value);
}
// Convert Set back to array and return it:
return [...candidates];
}
function pickRandomly(array) {
return array[Math.floor(Math.random()*array.length)];
}
$('#add').click(function () {
var used = getUsedNumbers();
var candidates = getCandidates(used);
// Safety:
if (!candidates.length) {
alert('No more candidate values available');
return;
}
var choice = pickRandomly(candidates);
// Insert the selected number at the top of the list:
$(".tfooter").prepend(
$("<div>").addClass("boxA").text(choice).attr({
id: "bx"+choice, value: choice
})
);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">Add</button>
<div class="tfooter">
</div>
If you do this repeatedly, then it is not so efficient to re-read the list of values from the page each time, since you actually know what is there already.
Consider making the candidates Set the master reference for your data, and only depend on that to generate the output.
You need to use $.inArray() to check if the random number exists in an existing array or not. if the number doesn't exist, it adds that random number to the array. Below is an updated code:
$("#generateNewNumber").on('click', function() {
var newArray = [];
$(".boxA").each(function() {
newArray.push(parseInt($(this).attr('value')));
});
var randomNumber = Math.ceil(Math.random() * 50);
console.log('Random number is: ' + randomNumber);
if ($.inArray(randomNumber, newArray) !== -1) {
console.log(randomNumber + ' exisits in array');
} else {
newArray.push(parseInt(randomNumber));
$(".tfooter").append('<div class="boxA" id="bx' + randomNumber + '" value="' + randomNumber + '">' + randomNumber + '</div>')
console.log(randomNumber + " doesn't exisits in array, hence adding in an array.");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="generateNewNumber">Generate Random Number</button>
<div class="tfooter">
<div class="boxA" id="bx3" value="3">3</div>
<div class="boxA" id="bx27" value="27">27</div>
<div class="boxA" id="bx46" value="46">46</div>
<div class="boxA" id="bx40" value="40">40</div>
<div class="boxA" id="bx42" value="42">42</div>
<div class="boxA" id="bx29" value="29">29</div>
<div class="boxA" id="bx13" value="13">13</div>
<div class="boxA" id="bx1" value="1">1</div>
</div>
Here is how I would had set up the code:
Create the array with numbers 1-50 in it.
Create a random number based on the list's length.
Randomly splice a position. That position will then be removed from the array but return a an array with one item.
If the array is empty (length 0), start over at 1.
Then you don't need to check if the number exists, because it has already been removed from the array.
function createBoxNumbersArray(startNumber, endNumber) {
var boxNumbers = [];
for (var i = startNumber; i <= endNumber; i++) {
boxNumbers.push(i);
}
return boxNumbers;
}
function getRandom(boxNumbers) {
position = Math.floor((Math.random() * boxNumbers.length-1));
return boxNumbers.splice(position, 1)[0];
}
var boxNumbers = createBoxNumbersArray(1, 50);
var randomBoxNumber = getRandom(boxNumbers);
Seems like indexOf would be the way to go. Your problem is that you're probably comparing the HTML attribute value (a string) to the random number (a number).
so, once you update to:
array.push(parseInt(dNumber));
You will be able to check
if(array.indexOf(randomnumber) >= 0) { } // regenerate random
And how do I get it to display the number, not undefined?
It's a tipping app. The user inputs the price of whatever it is they bought (pizza, haircut, etc.) in #price, then calcTip() calculates the tip, sends it over to calcTotal() which calculates the total, and sends it over to displayAmounts().
I don't know exactly what happens, but something messes up with the variable tip. calcTip() works correctly and calculates the tip amount successfully. I know this because the JavaScript console displays the amount when I input tip;. However, on the page, #tipSpan displays the tip as undefined.
What baffles me most is that the variable total works perfectly fine.
Does anyone know what might be going on or how I can fix it?
Here is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tipping App</title>
<style>
<!-- Temporary -->
#error {
display: none;
}
</style>
</head>
<body>
<div id="wrapper">
<header>
<h1>Tipping App</h1>
</header>
<section>
<div class="price">
<h2>Price Information</h2>
<label for="priceInput">Enter the price below!</label><input id="priceInput" type="text"><button id="calcButton">Calculate the Tip</button>
<p id="error">Error: You need to enter the cost!<br><br>Use only numbers and decimal points, no currency symbols or letters.</p>
</div>
<div id="tipContainer" class="tip">
<h2>Tip Information</h2>
<p id="tipPara">Your tip should be... <span>$<span id="tipSpan"></span></span></p>
</div>
<div id="totalContainer" class="total">
<h2>Total Information</h2>
<p id="totalPara">Your total is... <span>$<span id="totalSpan"></span></span></p>
</div>
</section>
</div>
<script src="js/app.js"></script>
</body>
</html>
Here is the JavaScript:
///// VARIABLES
//////////////////////////////
var priceInput = document.getElementById("priceInput");
var calcButton = document.getElementById("calcButton");
var error = document.getElementById("error");
var tipContainer = document.getElementById("tipContainer");
var tipPara = document.getElementById("tipPara");
var tipSpan = document.getElementById("tipSpan");
var totalContainer = document.getElementById("totalContainer");
var totalPara = document.getElementById("totalPara");
var totalSpan = document.getElementById("totalSpan");
var tip;
var total;
///// FUNCTIONS
//////////////////////////////
function calcTip() {
var price = priceInput.value; // This is the price the user inputs
var minTip = (Math.ceil(price * .15)); // Calculates a 15% tip rounded up to the nearest dollar
var maxTip = (price * .2); // Calculates a 20% tip
if (isNaN(price) || price === "") {
// If the user doesn't enter a number
// Or doesn't enter anything,
// Then display the error message
error.style.display = "block";
return;
} else {
error.style.display = "none";
if (maxTip < minTip) {
// If the 20% tip is less than the 15% rounded tip,
// Then let's go with that 20% tip
calcTotal(price, maxTip);
tip = maxTip;
} else {
// Otherwise, let's just do the 15%
calcTotal(price, minTip);
tip = minTip;
};
};
};
function calcTotal(price, tip) {
// Add the price and the tip together to yield the total
price = parseInt(price);
tip = parseInt(tip);
total = (price + tip);
displayAmounts();
}
function displayAmounts() {
// Update the page to display the tip and the total to the user
tipContainer.style.display = "block";
totalContainer.style.display = "block";
tipSpan.innerText = tip;
totalSpan.innerText = total;
}
///// EVENTS
//////////////////////////////
calcButton.addEventListener("click", calcTip);
Also, unrelated, but does my JavaScript look good? Is it clean code? I hope to find a web development job in the near future, and I know I need to be good at JavaScript.
WORKING DEMO
Update the function arguments
function calcTotal(price, maxTip) {
// Add the price and the tip together to yield the total
price = parseInt(price);
tip = parseInt(maxTip);
total = (price + tip);
displayAmounts();
}
Here the argument tip is overriding the global variable. Replace it to maxTip as you call.
1) In function displayAmounts, pass parameters tip & total
2) Instead of
tipSpan.innerText = tip,
TRY WITH
tipSpan.innerHTML = tip;
and same for total ,
use totalSpan.innerHTML = total
instead of
totalSpan.innerText ;
Then it should work
Try changing your method definition so it passes the values in:
displayAmounts(); should become displayAmounts(tip, total);
See the fiddle here.
Also you should use parseFloat rather than parseInt assuming you'll want to be more accurate than whole numbers.
Just a small mistake!
Instead of:
calcTotal(price, minTip);
tip = minTip;
Do:
tip = minTip;
calcTotal(price, minTip);
This way tip is calculated before displayAmounts is run.
Abut your code:
This is fine with just getting started. I recommend going through w3school's tutorials on javascript. The more you use javascript, the better you will get.
If you want a learning path I would recommend taking, let me know.
innerText works only on IE. textContent is W3C-compliant, but if you want your code to be standards compliant and cross-browser safe you should use this:
while( tipSpan.firstChild ) {
tipSpan.removeChild( tipSpan.firstChild );
}
tipSpan.appendChild( document.createTextNode(tip) );
Do this for totalSpan also.
I'm trying to find the total amount group by data attribute name from a list using jQuery. Similar to grouping categories and find the sum.
For example, I would like to create something like this:
group1 = 3
group2 = 5
group3 = 3
from this list:
<span class="data-center" data-category="group1" data-amount="1"></span>
<span class="data-center" data-category="group2" data-amount="1"></span>
<span class="data-center" data-category="group2" data-amount="2"></span>
<span class="data-center" data-category="group1" data-amount="2"></span>
<span class="data-center" data-category="group2" data-amount="2"></span>
<span class="data-center" data-category="group3" data-amount="3"></span>
I wonder if there is some jQuery function help to achieve it, something like groupByName()?
Using pure JavaScript:
Example Here
function getCategoryTotal(cat) {
var total = 0,
elements = document.querySelectorAll('[data-category="' + cat + '"]');
Array.prototype.forEach.call(elements, function (el, i) {
total += parseInt(el.dataset.amount, 10);
});
return total;
}
console.log(getCategoryTotal('group1')); // 3
console.log(getCategoryTotal('group2')); // 5
console.log(getCategoryTotal('group3')); // 3
I guess you asked about a jQuery way of doing so, which I did:
$.fn.amountByData = function(dataAttr, amountDataAttr) {
if (typeof amountDataAttr == "undefined")
amountDataAttr = "amount";
var dataAmountArr = new Array();
$(this).each(function() {
var dataAttrVal = $(this).data(dataAttr);
if (typeof dataAmountArr[dataAttrVal] == "undefined")
dataAmountArr[dataAttrVal] = parseInt($(this).data(amountDataAttr));
else
dataAmountArr[dataAttrVal] += parseInt($(this).data(amountDataAttr));
});
return dataAmountArr;
};
Here's how I would achieve it jQuery way ! This gives a LOT of flexibility, because you can choose by which data attribute you want to calculate the amount based on, and you can also choose to precise a different amount data attribute if it is not named amount.
PS: I know an answer has already been chosen, but contrary to #Josh Crozier, I understood you wanted a jQuery method to achieve your goal.
Cheers,
Long story short, I want to create a very basic search in my Html div.
Each possible search tag starts and ends with $. Each tag is unique.
My goal is to create a function that takes a tag, search through the div, find the line (Y position) of that tag in the div.
Only problem is to get the line position of a string. I can find if the string is there, but I have no information about its position in the div.
(In the example, it is represented by getLineWhereTagIsFound(tag) ).
Note: I could possibly count the amount of <br> until I find the tag but I don't know how reliable it would be.
This is what I have so far.
<div id="helpText" class='onlyTextScroll container'>
$Fruits$<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
Fruits are very nice.<br>
<br>
$Vegetables$<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
Vegetables are very evil.<br>
<br>
</div>
<script>
function updateHelp(tag){
var y = getLineWhereTagIsFound('$' + tag + '$');
y *= lineHeight;
$("#helpText").scrollTop(y);
}
/* Example
function updateHelp('Vegetables'){
var y = getLineWhereTagIsFound('$' + 'Vegetables' + '$');
//y would be 10 because $Vegetables$ is found on line 10;
//let say lineHeight is 10;
y = y*lineHeight; //10*10
$("#helpText").scrollTop(100);
}
*/
</script>
function getLineWhereTagIsFound(tag){
var helpText = document.getElementById("helpText");
var count = 0;
for(var i=0;i<helpText.childNodes.length;i++){
if(helpText.childNodes[i].nodeType==3){
count++;
if(helpText.childNodes[i].nodeValue.indexOf(tag)>=0){
break;
}
}
}
return count;
//count would be 11,not 10, because $Vegetables$ is found on line 11
//each <br/> one line
}