Live calculate time from inputs - javascript

Question: so im doing a timesheet and i have 3 inputs with start, end and break and would like to do a live calculate with it but it need to be with a : i have found some live calculator but non of them is time based and can take :
so the question how would i do it?
so this is what i got but it does not do time :
http://jsfiddle.net/5xzSy/1848/
Example: 08:00(start)10:00(end)01:00(break) and that would be 01:00(total)
so end-start-break=total

var start = $('#start'),
end = $('#end'),
brk = $('#break'),
total = $('#added'),
timespan;
$('input').keyup(function() { // run anytime the value changes
var e = toMins(end.val()),
s = toMins(start.val()),
b = toMins(brk.val());
if (!s || !e) return;
var output = (e - s - b) / 60;
total.html(Math.floor(output) + ':' + toDouble(Math.round((output % 1) * 60)));
});
function toMins(val) {
if (!val) return 0;
val = val.split(':');
return (Number(val[0]) * 60) + Number(val[1] || 0);
}
function toDouble(n) {
return n < 10 ? ('0' + n) : n;
}
table { margin: 10px; }
table td { padding: 2px 4px; }
input { width: 60px; padding: 2px 4px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr><td>Start:</td><td><input id=start placeholder="hh:mm"></td></tr>
<tr><td>End:</td><td><input id=end placeholder="hh:mm"></td></tr>
<tr><td>Break:</td><td><input id=break placeholder="hh:mm"></td></tr>
<tr><td>Total:</td><td><span id=added></span></td></tr>
</table>

I recommend you tu use a framework like Angular or VueJS that make that kind of requirements easier
https://vuejs.org/
https://angular.io/

Related

how to make a stimulus (image, div, whichever's easiest) show up on right or left half of screen randomly using javascript

how to make a stimulus (image, div, whichever's easiest) show up on right or left half of screen randomly using javascript.
Any ideas about having the button clicks record the reaction time, which button is clicked (left or right), and which side the stimulus was presented on?? Also, the left button should be "true" when stimulus is presented on the right and vice versa.
<head>
<style >
.divStyleLeft {
width: 300px;
height: 300px;
background-color: lightblue;
float: left;
}
.divStyleRight {
width: 300px;
height: 300px;
background-color: lightgreen;
float: right;
}
.maxWidth {
width: 100%;
}
.button {
float: right;
}
.button2 {
float: left;
}
</style>
</head>
<body onload="presentStimulus()">
<div class="button">
<button onclick="presentStimulus()">Click Me</button>
</div>
<div class="button2">
<button onclick="presentStimulus()">Click Me </button>
</div>
<div class="maxwidth"></div>
<div id="float" class="divStyleLeft" onclick="recordClick()">
I AM NOT FLOATING
</div>
<script>
let numClicks= 0;
let timeStart = 0;
let timeEnd = 0;
function Trial(trialTime, sidePresented,buttonClicked,) {
this.trialTime = trialTime;
this.sidePresented= sidePresented;
this.buttonClicked= buttonClicked;
}
let allTrials = [];
for(x = 0; x < 12; x++)
allTrials.push(new Trial(0,0,0));
Trial.prototype.toString=function(){
return this.trialTime + "ms, Side : " + this.sidePresented + ", Reaction Time: " + this.buttonClicked
+ "<br>";
};
function presentStimulus() {
const elem = document.querySelector ( '#float' );
const min = 1;
const max = 2;
const v = Math.floor(Math.random() * (max - min + 1)) + min;
console.log ( 'Random num is ' + v + ": ", '1 will go left, 2 will go right' );
v === 1 ?
( () => {
elem.classList = [ 'divStyleLeft' ];
elem.innerText = 'Hello!';
} ) () :
( () =>{
elem.classList = [ 'divStyleRight' ];
elem.innerText = 'Hi!';
} ) ();
}
function recordClick()
{
let theData = document.getElementById("#float").data;
timeEnd = Date.now();
allTrials[numClicks].trialTime = timeEnd - timeStart;
allTrials[numClicks].sidePresented = theData.sidePresented;
allTrials[numClicks].buttonClicked = theData.buttonClicked;
if (numClicks < 11) {
numClicks++;
presentStimulus();
}
else {
document.getElementById("float").style.visibility = "hidden";
let output = "";
for (x = 0; x < allTrials.length; x++)
output = output + "<b>:" + (x + 1) + "</b>:" + allTrials[x].toString();
document.getElementById("display").innerHTML = output;
}
}
</script>
<p id="display"></p>
</body>
There's a bunch of ways you could go about this.
If you're using plain 'ol JS, I'd probably create classes in CSS that float left or right, possibly appear as a flex container that displays left or right, whatever your specific need might be (again, there's a lot of ways to go about it, and one might be better than the other given your context).
When you've determined left or right (gen a random number or whatever), update the classlist on the DOM elements with the desired class to make it go this way or that.
For what it's worth, here's a bare-bones vanilla JS example. Again, I don't know your specific context, but this should give you a start on how to look at it. Floating may not be ideal, you may want to just hide/show containers that already exist on the left or right or actually create whole new DIVs and insert them into known "holder" containers (usually just empty divs), but the idea is the same; gen the random number, alter the classlists of the elements you want to hide/show/move/whatever, and if necessary, alter the innerHTML or text as needed.
<html>
<head>
<style>
.divStyleLeft {
width: 300px;
height: 300px;
background-color: lightblue;
float: left;
}
.divStyleRight {
width: 300px;
height: 300px;
background-color: lightgreen;
float: right;
}
.maxWidth {
width: 100%;
}
</style>
</head>
<body>
<button onclick="onClick()">Click Me</button>
<div class="maxwidth">
<div id="floater" class="divStyleLeft">
I AM NOT FLOATING
</div>
<div>
<script>
function onClick () {
const elem = document.querySelector ( '#floater' );
const min = 1;
const max = 2;
const v = Math.floor(Math.random() * (max - min + 1)) + min;
console.log ( 'Random num is ' + v + ": ", '1 will go left, 2 will go right' );
v === 1 ?
( () => {
elem.classList = [ 'divStyleLeft' ];
elem.innerText = 'I am floating LEFT';
} ) () :
( () =>{
elem.classList = [ 'divStyleRight' ];
elem.innerText = 'I am floating RIGHT';
} ) ();
}
</script>
</body>
</html>

How to attach an element on the dynamically created div

I am a guitar addict and I try to make a UI for guitar tablature.
In my js code, you can see
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8',
's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
's6f1' means string 6 & fret 1 and I want to show it on tablature. The way I show this is to put a "1" on string 6. Please the picture below. In my code, I basically traverse the notes array and attach each note on tablature . I define each 6 six lines as a group. After a group is filled with 4 notes, a new group is shown. Since In my real application, I do not know how many notes that notes array has(In this examples, I just simplify there are 15 notes), I have to dynamically create each group and assign each line a unique id. My question is that I do not know how to attach the number on the string. For instance, after dynamically create a "six-line", how do I attach the number on the correct line. I think the challenge in my question is that I cannot predefine the location of six-liner in html. The code below is the html, css, js code that I wrote. Hope someone could help me out. Thank you in advance.
html:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="code.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="code_js.js"></script>
</head>
<body>
</div>
<div id = "output">
</body>
</html>
css:
.deco {
border-bottom: 1px solid black;
width: 120px;
margin-left:0px;
margin-bottom:10px;
z-index: 2;
position: relative;
display: block;
margin-right: 20px;
}
#output {
width: 300px;
height: 200px;
position:absolute;
float:left;
background-color: yellow;
}
.six_line {
width: 125px;
height: 80px;
float:left;
margin-right: 20px;
}
js:
"use strict"
var count = 0;
var group = -1;
$(document).ready(function() {
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
hideNote(notes, 0);
});
function hideNote(notes, i) {
var x = -2;
if(count == 4) {count = 0;}
if(count++ == 0) {
group++;
makeItHappen();
}
var ns4 = notes[i];
// retrive the info of string
var ns2 = ns4.substring(0,2);
x = parseInt(ns4.substring(1,2)) + (group*6);
**/*How to attach fret(#) on the string*
// finds the line with corresponding id
$('#hr' + x).attr('class', '?');
*/**
hide(function(){
if(++i < notes.length) {
hideNote(notes, i);
}
},notes[i]);
}
function hide(callback, note) {
setTimeout(function(){
callback();
}, 1000);
}
function makeItHappen() {
var six = document.createElement('div');
six.className = "six_line";
for (var i = 1; i < 7; i++) {
var hr = document.createElement('hr');
hr.className = "deco";
hr.id = "hr" + (group * 6 + i);
six.append(hr);
}
$('#output').append(six);
}
I suggest some modifications in your code.
Starting with the function that creates your strings:
function makeItHappen(nbGroup) {
for(var g = 1; g <= nbGroup; g++){
var six = document.createElement('div');
six.className = "six_line";
for (var i = 6; i >= 1; i--) {
var string = document.createElement('div');
string.className = "deco";
string.id = "string" + ('G' + g + 'S' + i);
six.append(string);
}
$('#output').append(six);
}
}
That will create all your groups of strings at the same time. It becomes easily to attribute an explicit ID for each of them : strGiSj where i is the group and j the string in the group.
Next, how about the hideNode function:
function hideNote(notes) {
makeItHappen(Math.ceil(notes.length / 4));
notes.forEach(function(n, i){
var values = n.match(/s(\d)f(\d)/); // values[1] = string, values[2] = fret
var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
var child = $("<div></div>")
.addClass("fret")
.css("left", (10+ (i%4) * 25) + "px")
.text(values[2]);
parentEl.append(child)
});
}
We create the amount of groups needed (amount of notes / 4 rounded to next int). For each note in your array, we retrieve the string and the fret with a regular expression /s(\d)f(\d+)/:
\d matches a digit
\d+ matches one or more digits
Parenthesis allow to retrieve values easily
Next, we just have to retrieve the appropriate group, and retrieve the associated div with good id, then create the fret element and place it.
The full code looks like this:
"use strict"
$(document).ready(function() {
var notes = ['s6f1', 's5f5', 's4f7', 's3f6', 's2f5', 's1f3', 's6f8', 's5f1', 's4f6', 's3f1', 's2f3', 's1f3', 's6f9', 's5f17', 's4f19'];
hideNote(notes);
});
function hideNote(notes) {
makeItHappen(Math.ceil(notes.length / 4))
notes.forEach(function(n, i){
var values = n.match(/s(\d)f(\d+)/);
var parentEl = $("#stringG" + (Math.ceil((i + 0.5) / 4)) + "S" + values[1]);
var child = $("<div></div>")
.addClass("fret")
.css("left", (10+ (i%4) * 25) + "px")
.text(values[2]);
parentEl.append(child)
})
}
function makeItHappen(nbGroup) {
for(var g = 1; g <= nbGroup; g++){
var six = document.createElement('div');
six.className = "six_line";
for (var i = 6; i >= 1; i--) {
var string = document.createElement('div');
string.className = "deco";
string.id = "string" + ('G' + g + 'S' + i);
six.append(string);
}
$('#output').append(six);
}
}
Here is a codepen with a working sample.

Trying to make a reusable function to make cells in a row. (chess board)

I'm trying to make the first row of a chess board. I had it but Im trying to make what I think what's called a constructor function to learn more advanced programming. I'm trying to get all the data in the function and append the div to the board the x should be updated by multiplying i * the piece size.I think I'm having problems using the new key word and appending together. If you could show me how you would fill up the whole chess board that would be great. I'm assuming you would use nested for loops. That's my next goal.
I have something like this.
$(function(){
var boardHeight = parseInt($(".board").css("height")),
boardWidth = parseInt($(".board").css("width")),
amountOfPieces =8,
pieceSize = boardHeight / amountOfPieces,
board = $(".board");
console.log(pieceSize);
function Cell(orange, x){
this.width = pieceSize;
this.height = pieceSize;
this.color = orange ? "orange" : "black"
this.x = x;
}
console.log( new Cell())
for(var i = 0 ; i < amountOfPieces; i++){
if(i % 2 == 0){
board.append($("<div>") new cell("orange", i * pieceSize))
}else if( i % 2 == 1){
board.append($("<div>").css({
position: "absolute",
width : pieceSize,
height: pieceSize,
"background-color" : "black",
left: i * pieceSize
}))
}
}
});
EDIT: ok guys I got the first row shown in my answer. now I need to fill in the whole board. Remember the colors need to alternate and I would prefer to use a nested for loop. Thanks.
You should be passing pieceSize in as an argument like:
function Cell(orange, x, size) {
this.width = size;
this.height = size;
this.color = orange ? "orange" : "black"
this.x = x; // What is x used for anyway?
}
Then when you use it, it would look something like (just an example):
var createdCell = new Cell(true, 0, pieceSize);
Also the following line is all messed up on multiple levels:
board.append($("<div>") new cell("orange", i * pieceSize))
Take a look at the jQuery .append() documentation to get a better understanding of how to use it: http://api.jquery.com/append/
All your Cell constructor function does is create objects with the parameters of one space on the game board. It doesn't actually build it. You'll need to create a function that takes in the object produced by new Cell() an actually creates a string of HTML for you to append to the page. Something like:
function create(cell) {
var str = '<div class="whatever" style="';
str+= 'height: ' + cell.height + ';';
str+= 'width: ' + cell.width + ';';
str+= 'background: ' + cell.color + ';';
'">';
str += '</div>';
return str;
}
Then you could do something like:
board.append(create(new Cell(true, 0, pieceSize)))
This answer is not something for you to copy/paste into your project. These are examples to give you the tools you'll need to solve this problem.
Ok I came up with this answer. what do you think?
$(function(){
var boardHeight = parseInt($(".board").css("height")),
boardWidth = parseInt($(".board").css("width")),
amountOfPieces =8,
pieceSize = boardHeight / amountOfPieces,
board = $(".board");
console.log(pieceSize);
function Cell(orange, x){
this.width = pieceSize;
this.height = pieceSize;
this.background = orange ? "orange" : "black"
this.left = x;
this.position = "absolute"
}
console.log( new Cell())
for(var i = 0 ; i < amountOfPieces; i++){
if(i % 2 == 0){
var obj = new Cell("orange", i * pieceSize)
console.log(obj)
board.append($("<div>").css(obj))
}else if( i % 2 == 1){
var obj = new Cell("",i * pieceSize )
board.append($("<div>").css(obj))
}
}
})
.board{
background: #ccc;
width: 500px;
height: 500px;
margin: 20px auto;
position: relative;
}
.cell{
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div class="board"></div>
Now on to making the columns. any help with that guys?
EDIT: I came up with an answer to fill the whole board and it is below. I still would like to see other people's results
$(function(){
var boardHeight = parseInt($(".board").css("height")),
boardWidth = parseInt($(".board").css("width")),
amountOfPieces =8,
pieceSize = boardHeight / amountOfPieces,
board = $(".board");
console.log(pieceSize);
function Cell(orange, x, y){
this.width = pieceSize;
this.height = pieceSize;
this.background = orange ? "orange" : "black"
this.left = x;
this.position = "absolute"
this.top = y
}
console.log( new Cell())
for(var i = 0; i < amountOfPieces ; i ++){
for(var j = 0 ; j < amountOfPieces; j++){
if(i % 2 == 0){
if(j % 2 == 1){
var obj = new Cell("orange", i * pieceSize , j * pieceSize)
console.log(obj)
board.append($("<div>").css(obj))
}else{
var obj = new Cell("", i * pieceSize , j * pieceSize)
console.log(obj)
board.append($("<div>").css(obj))
}
}else if( i % 2 == 1){
if(j % 2 == 1){
var obj = new Cell("", i * pieceSize , j * pieceSize)
board.append($("<div>").css(obj))
}else{
var obj = new Cell("orange", i * pieceSize , j * pieceSize)
board.append($("<div>").css(obj))
}
}
}
}
})
.board{
background: #ccc;
width: 500px;
height: 500px;
margin: 20px auto;
position: relative;
}
.cell{
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<div class="board"></div>
Try using .slice(), .filter(), :odd, :even, .addBack(), Array.prototype.reverse()
for (var i = n = 0, colors = ["orange", "black"]; i < 64; i++, n = i % 8 + 1) {
$("<div class=row>").appendTo("section");
if (n === 8) {
$(".row").slice(i === n - 1 ? 0 : $(".row").length - n, i + 1)
.filter(":even").css("background", colors[0])
.addBack().filter(":odd").css("background", colors[1]);
colors.reverse(); $("section").append("<br>");
}
}
div {
position: relative;
width: 65px;
height: 65px;
display: inline-block;
padding: 0;
margin-left: 2px;
margin-right: 2px;
outline: 2px solid brown;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<section>
</section>

hsl to rgb conversion. Values waaaay off. Compare to solution. What am I doing differently?

SOLVED! see EDITs
I built a color picker app. Very simple; you click on the rgb color palette, and it creates a swatch with RGB values, HSL values, and HEX values.
I used this formula for the conversions.
Basically, I built my HSL values from the x and y mouse positions with a static 99% saturation.
From there, I created the color palette to pick from by converting HSL to RGB.
A click event on the palette will create RGB, HSL, and HEX swatches along with the values for each.
Since I can't get the RGB and HSL values to match I haven't incorporated the HEX values yet.
I finally found a working solution. Can someone tell me where my calculations drift away from the working solution? I don't just want to accept the working solution and move on; I want to know where my logic starts to break down.
Thanks so much for any help!
EDIT: So Bob__ suggested I use a better way to normalize my RGB values instead of just adding or subtracting 1 depending on their values. I added this function to make the RGB channels based on the hue value(-0.333 - 360.333)
function normalizeRGB(color){
var newVal = (360.333 - (-0.333))/(360.333 - (-0.333)) *
(color- (-0.333) + (-0.333));
return newVal;
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Color Picker, Bro</title>
<link href='http://fonts.googleapis.com/css? family=Raleway:700,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
<script src='https://code.jquery.com/jquery-2.1.3.min.js'></script>
<script type="text/javascript" src='myColorPickerSol.js'></script>
<!-- <script type="text/javascript" src='actualWorkingColorPickerSol.js'></script> -->
</head>
<body>
<div id='container'>
<h1>Color Picker, bro</h1>
<section id='canvas'></section>
<section id='readout'>
<p>HSL: <span id='hsl'></span></p>
<section id='swatchhsl'></section>
<p>RGB: <span id='rgb'></span></p>
<section id='swatchrgb'></section>
<p>HEX: <span id='hex'></span></p>
</section>
</section>
</div>
</body>
</html>
style.css:
body {
background: url(http://subtlepatterns.com/patterns/subtle_white_mini_waves.png);
}
#container {
margin: 0 auto;
width: 800px;
height: inherit;
text-align: center;
font-family: Raleway;
font-weight: 300;
}
#canvas {
margin: 0 auto;
border: 5px solid black;
box-sizing: border-box;
height: 360px;
width: 360px;
}
#readout {
background: rgba(117,117,117, .2);
margin: 20px auto;
height: 400px;
width: 360px;
border: 1px #333 solid;
box-sizing: border-box;
border-radius: 20px;
}
#swatchhsl,#swatchrgb {
margin: 0 auto;
height: 75px;
width: 95%;
border-radius: 20px;
}
p, span {
letter-spacing: 1px;
}
p {
font-weight: 700;
}
span {
font-weight: 300;
}
myColorPickerSol.js
$(document).ready(function(){
var canvas = $('#canvas');
//swatch matches closest when either pure blue, green or red; loses all accuracy when colors mix.
// dark blue gets really close. Purple gets really close, which makes me suspect the Green channel value is where the problem lies.
// y-axis as Luminace(0-100%)
// x-axis as Hue(0-360)
var yPos;
var lum;
var hue;// aka xPos;
var temp1;//for hslToRGB
var temp2;//for hslToRGB
var tempR;
var tempG;
var tempB;
var red;
var blue;
var green;
var realColVal;
$('#canvas').mousemove(function(event){
hue = Math.abs(event.offsetX);
hueForRGB = (hue/360);
yPos = Math.abs(event.offsetY);
lum = (yPos/360);
// console.log(lum + ' lum');
$(canvas).css({'background-color':'hsl('+ event.offsetX + ',99%,'+ Math.round(lum *100) + '%)'});
});
// swatch listener
$(canvas).click(function(event){
hsl2RGB(lum);
$('#rgb').text(red + ','+ green + ',' + blue);
$('#hsl').text(hue + ',99%,' + Math.round(lum * 100) + '%');
$(canvas).css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
});
//red channel must be in upper third; green in middle third; blue in lower third.
function hsl2RGB(lum){
tempR = (hueForRGB + 0.333);
tempG = hueForRGB;
tempB = (hueForRGB - 0.333);
// set temporary lum based on whether it is above/below 50%
temp1 = lumMorOrLess50(lum);
// set secondary temporary lum value
temp2 = ((2.0 * (lum)) - temp1);
//-----------EDIT -----------------------------
// used the formula to make the tempR|G|B values between 0 and 1
// tempR = makeRGB01(tempR);
// tempG = makeRGB01(tempG);
// tempB = makeRGB01(tempB);
//-----------------------------------------------
red = Math.round(convert2RGB(tempR,temp1,temp2));
green = Math.round(convert2RGB(tempG,temp1,temp2));
blue = Math.round(convert2RGB(tempB,temp1,temp2));
//swatch appears on click for hsl and rgb
$('#swatchhsl').css({'background-color':'hsl('+ hue + ',99%,'+ Math.round(lum * 100 )+ '%)'});
$('#swatchrgb').css({'background-color':'rgb('+ red + ','+ green + ','+ blue + ')'});
};
//force tempR|G|B to be between 0-1
function makeRGB01(input) {
if(input > 1){
input -= 1.0;
} else if(input < 0){
input += 1.0;
};
return input;
};
//get value for each rgb channel
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6 * tempColVal);
console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
//-------EDIT ------------------------------------------
// test2 will set realColVal to val1 instead of tempColVal
//-------------------------------------------------------
} else if(2.0 * tempColVal < 1){
realColVal = val1;
console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
console.log(realColVal + 'test 3');
} else {
realColVal = val2;
console.log(realColVal + 'realColVal = default (temp 2)');
};
//-------EDIT ------------------------------------------
// normalize value before multiplying by 255
realColVal = normalizeRGB(realColVal);
//-------------------------------------------------------
// force value between 0 and 1 then set it to RGB scale and
// return
return (Math.abs(realColVal) * 255.0));
};
//configure temporary luminance value, temp1, based on luminance
function lumMorOrLess50(val){
if(val < 0.50){
return ((1.0 + 0.99) * val);
} else {
return ((.99 + val) - (val * .99));
};
};
});
This is the working solution, actualColorPickerSol.js What did I do differently?
$(function() {
console.log('Loaded, bro');
colorPicker();
});
function colorPicker() {
var canvas = $('#canvas');
canvas.on('mousemove', changeCanvasBackground);
canvas.on('click', printColorReadout);
}
function changeCanvasBackground(event) {
var xCoord = Math.abs(event.offsetX);
var yCoord = Math.abs(event.offsetY);
var rgbValues = 'rgb(' + rgb(hsl(xCoord, yCoord)) + ')';
$(this).css('background', rgbValues);
}
function printColorReadout(event) {
var xCoord = event.offsetX;
var yCoord = event.offsetY;
var hslValues = hsl(xCoord, yCoord);
var rgbValues = rgb(hslValues);
var hexValues = hex(rgbValues);
var hslString = parseHSL(hslValues);
var rgbString = parseRGB(rgbValues);
var hexString = parseHEX(hexValues);
$('#hsl').text(hslString);
$('#rgb').text(rgbString);
$('#hex').text(hexString);
$('#swatchhsl').css('background', hslString);
$('#swatchrgb').css('background', rgbString);
}
function hsl(xCoord, yCoord) {
// HSL = hsl(hue, saturation, luminance)
var hsl;
var hue = xCoord;
var luminance = Math.round(((yCoord / 360) * 100));
return [hue, 100, luminance];
}
function rgb(hslValues) {
var hue = hslValues[0];
var sat = hslValues[1] / 100;
var lum = hslValues[2] / 100;
var tempLum1, tempLum2, tempHue, tempR, tempG, tempB;
if (lum < .50) {
tempLum1 = lum * (1 + sat);
} else {
tempLum1 = (lum + sat) - (lum * sat);
}
tempLum2 = (2 * lum) - tempLum1;
tempHue = hue / 360;
tempR = tempHue + .333;
tempG = tempHue;
tempB = tempHue - .333;
//This is the only part I think I did differently.
//The code below makes sure the green and blue values
//are between 0 and 1, then it checks all the colors to
//make sure they are between 0 and 1. I tried this,
// and there was no change in the effect;
// the hsl and rgb values were still different.
if (tempG < 0) { tempG += 1};
if (tempG > 1) { tempG -= 1};
if (tempB < 0) { tempB += 1};
if (tempB > 1) { tempB -= 1};
var normalizedRGB = [tempR, tempG, tempB].map(function(color, idx) {
if (color < 0) { return color += 1};
if (color > 1) { return color -= 1};
return color;
});
var rgbArray = normalizedRGB.map(function(color) {
if (colorCondition1(color)) {
return tempLum2 + ( tempLum1 - tempLum2 ) * 6 * color;
} else if (colorCondition2(color)) {
return tempLum1;
} else if (colorCondition3(color)) {
return tempLum2 + (tempLum1 - tempLum2) * (.666 - color) * 6;
} else {
return tempLum2;
}
});
var rgbValues = rgbArray.map(function(color, idx) {
var convertedVal = color * 255;
return Math.round(convertedVal);
});
return rgbValues;
}
function hex(rgbValues) {
var r = rgbValues[0];
var g = rgbValues[1];
var b = rgbValues[2];
return [numToHex(r), numToHex(g), numToHex(b)];
}
function numToHex(num) {
var hexCode = num.toString(16);
if (hexCode.length < 2) { hexCode = "0" + hexCode; }
return hexCode;
}
function colorCondition1(val) {
return 6 * val < 1;
}
function colorCondition2(val) {
return 2 * val < 1;
}
function colorCondition3(val) {
return 3 * val < 2;
}
function parseHSL(hslValues) {
return [
"hsl(",
hslValues[0], ", ",
hslValues[1], "%, ",
hslValues[2], "%)"
].join('');
}
function parseRGB(rgbValues) {
return "rgb(" + rgbValues.join(', ') + ")";
}
function parseHEX(hexValues) {
return "#" + hexValues.join('');
}
Comparing your functions to the algorythm presented in the link you posted, I think that a more correct implementation of convert2RGB, as I told in my comments, may be:
function convert2RGB(tempColVal, val1, val2){
//first convert tempColVal to between 0 and 1 then make it an RGB value
tempColVal = makeRGB01(tempColVal);
//next run 3 test;
if(6.0 * tempColVal < 1){
realColVal = (val2 + (val1 - val2) * 6.0 * tempColVal);
// console.log(realColVal + 'test 1; val1: '+ val1 + 'val2: ' + val2 );
} else if(2.0 * tempColVal < 1){
realColVal = val1;
// console.log(realColVal + 'test 2');
} else if(3.0 * tempColVal < 2){
realColVal = (val2 + (val1 - val2)*(0.666 - tempColVal) * 6.0);
// console.log(realColVal + 'test 3');
} else {
realColVal = val2;
// console.log(realColVal + 'realColVal = default (temp 2)');
};
// Convert them to 8-bit by multiply them with 255 and return
return Math.round(realColVal * 255.0);
};
Edit:
Don't change your makeRGB01(), in that algorythm is used in the same way you did before calling convert2RGB(). Your mistake is applying that to returned corrected value too.

JavaScript non-blocking updates to page

I have the following code that runs a loop and updates the page as it goes. At the moment the page does not update until the entire loop has run its course.
As you can see, I tried adding a draw function drawValues that is called every 5000 times to draw the current values to the screen. My understanding is that when drawValues is updated, the page should update and then the main loop will resume with its calculations until another 5000 loops.
At the moment the page will not update until the loop runs in its entirety, somehow ignoring every other call to drawValues
Full Snippet:
/*jslint browser: true*/
/*global $, jQuery, alert*/
$(document).ready(function() {
'use strict';
var namesAtStart = ["Sam", "John"],
specialNum = 8,
amountOfNames = namesAtStart.length,
counter = [],
renderCounter = 0,
x,
a,
loopLength,
number,
id,
preId = "content_",
finalId;
for (a = 0; a < amountOfNames; a += 1) {
counter.push(0);
}
for (x = 1; x <= specialNum; x += 1) {
// Start the counter array at zero
for (a = 0; a < amountOfNames; a += 1) {
counter[a] = 0;
}
loopLength = Math.pow(10, x);
finalId = preId + loopLength.toString();
$(".output-small").append('<span id="' + finalId + '"></span>');
for (a = 0; a < loopLength; a += 1) {
number = Math.floor((Math.random() * amountOfNames) + 1);
counter[number - 1] += 1;
renderCounter += 1;
if (renderCounter == 5000) {
drawValues(namesAtStart, counter, finalId, x, a);
}
if (a == loopLength - 1) {
// This is where I am trying to make the code non blocking and async
drawValues(namesAtStart, counter, finalId, x, a);
}
}
}
});
// This is the part that I want to run when called and update page.
function drawValues(names, counter, finalId, id, currentCount) {
'use strict';
var a;
$("#" + finalId).empty();
$("#" + finalId).append("<h3>" + Math.pow(10, id).toLocaleString() + "</h1>");
for (a = 0; a < names.length; a += 1) {
$("#" + finalId).append(
names[a] + ": " + counter[a].toLocaleString() + " (" + (counter[a] / currentCount * 100).toFixed(2) + "%)</br>"
);
}
$("#" + finalId).append("Numerical Difference: " + Math.abs(counter[0] - counter[1]) + "</br>");
$("#" + finalId).append(
"Percentage Difference: " + Math.abs(
(counter[0] / currentCount * 100) - (counter[1] / currentCount * 100)
).toFixed(6) + "%</br>"
);
$("#" + finalId).append("</br>");
}
body {} p,
h3 {
padding: 0px;
margin: 0px;
}
.container {} .output {} .output-small {
margin: 20px;
padding: 5px;
border: 1px solid rgba(0, 0, 0, 1);
width: 300px;
border-radius: 10px;
}
#stats-listing {}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<title>Roll The Dice</title>
<body>
<div class="container">
<div class="output" id="stats-listing">
<div class="output-small"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="logic.js"></script>
</body>
</html>
The main UI thread in browsers, which is used to run JavaScript, is single-threaded. So if you have a function that's taking a lot of time, the browser doesn't update the display.
To give the browser a chance to update the display, you need to yield back to it by letting your current function end and scheduling a timed callback to another run of it for the next block of updates, via setTimeout. You'll have to experiment with the browsers you want to support to determine the delay in the timed callback; some browsers are happy with 0 (call back as soon as possible), others want longer (50 — 50 milliseconds — is plenty for every browser I know).
Here's a simple example that adds 10 boxes to the page, yields, then adds another 10, yields, etc. until it's done 1,000 boxes:
(function() {
var total = 0;
addBoxes();
function addBoxes() {
var n;
for (n = 0; n < 10 && total < 1000; ++n, ++total) {
box = document.createElement('div');
box.className = "box";
document.body.appendChild(box);
}
if (total < 1000) {
setTimeout(addBoxes, 10); // 10ms
}
}
})();
.box {
display: inline-block;
border: 1px solid green;
margin: 2px;
width: 20px;
height: 20px;
}

Categories

Resources