Javascript: build css linear gradient with separator between strip - javascript

I have this code for build a linear gradient by array of colors (unknown length):
const colors = ['red', 'green', 'violet'];
const strips = [];
let start = 0;
let end = 0;
const stripPerc = Math.ceil(100 / colors.length);
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
start = end;
end = start + stripPerc;
if ( end > 100 ) {
end = 100;
}
let strip = color + ' ';
strip += start + '% ';
strip += end + '% ';
strips.push(strip.trim());
}
document.getElementById('foo').style.backgroundImage = 'linear-gradient(135deg, ' + strips.join(',') + ')';
div {
display: block;
width: 100%;
height: 50px;
}
<div id="foo"></div>
i want add a small (1%) white stripe between the colors:
const colors = ['red', 'green', 'violet'];
const strips = [];
let start = 0;
let end = 0;
const stripPerc = Math.ceil(100 / colors.length);
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
start = end;
end = start + stripPerc;
if ( end > 100 ) {
end = 100;
}
let strip = color + ' ';
strip += start + '% ';
strip += end + '% ';
strips.push(strip.trim());
strips.push(' white ' + end + '% '+ (end+1) +'%');
end++;
}
document.getElementById('foo').style.backgroundImage = 'linear-gradient(135deg, ' + strips.join(',') + ')';
div {
display: block;
width: 100%;
height: 20px;
}
<div id="foo"></div>
it works, but now the total length is over the 100%. How fix it?

I refactored your code a little bit, but logic is the same as expected - you should take in account white stripes width to calculate colored stripes width https://jsbin.com/supikoz/edit?html,js,output
const coloredWidth = 100 - stripWidth * (colors.length - 1);
const stripPerc = Math.ceil( coloredWidth / colors.length);

You can use flexbox for this. Accodording to your needs, you can style it or add white space. The trick is to use space-between. I would recommend doing the calculation with js and the placement with css.
const colors = ['red', 'green', 'violet'];
const stripPerc = Math.ceil(100 / colors.length) - 1;
colors.forEach(color => {
let strip_element = document.createElement('div');
strip_element.style.background = color;
strip_element.style.width = stripPerc + '%';
document.getElementById('flex').appendChild(strip_element);
})
#flex {
display: flex;
justify-content: space-between;
width: 100%;
height: 50px;
position:relative;
}
<div id='flex'>
</div>

Related

Isolate color of single character

I have a piece of code in p5.js that acts as a video filter:
const density = ' .:░▒▓█'
//const density = ' .tiITesgESG'
//let geist;
let video
let asciiDiv
let playing = false
let button
function preload() {
video = createVideo('assets/ripple.mp4', vidLoad)
}
function vidLoad() {
video.loop()
video.volume(0)
}
function setup() {
noCanvas()
//video = createCapture(VIDEO)
//video = createVideo('assets/01.mp4');
button = createButton('play');
button.mousePressed(toggleVid);
video.size(256, 160)
//video.size(160, 160);
asciiDiv = createDiv();
}
function toggleVid() {
if (playing) {
video.pause();
button.html('play');
} else {
video.loop();
button.html('pause');
}
playing = !playing;
}
function draw() {
background(0);
video.loadPixels();
let asciiImage = '';
//pixelarray
for (let j = 0; j < video.height; j++) {
for (let i = 0; i < video.width; i++) {
const pixelIndex = (i+j*video.width) * 4;
const r = video.pixels[pixelIndex + 0];
const g = video.pixels[pixelIndex + 1];
const b = video.pixels[pixelIndex + 2];
const avg = (r + g + b) / 3;
const len = density.length;
const charIndex = floor(map(avg, 0, 255, len, 0));
const c = density.charAt(charIndex);
if (c == ' ') asciiImage += ' '
else asciiImage += c;
}
asciiImage += '<br/>'
//console.log(row);
}
asciiDiv.html(asciiImage)
}
and CSS that looks like:
html, body {
margin: 0;
padding: 0;
border: 10px solid black;
background-color: #fff;
/*
//#fcbf45;
//aaaaaa;
*/
color: #000;
//#ffd & #00b0aa;
font-family: 'Courier Bold';
line-height: 4pt;
font-size: 5pt;
}
canvas {
display: block;
}
Which looks like
this
I apologize for all the comments.
My question is - if I use the color property in CSS, it will change the colors of all the characters. Is it possible to change the color of just one character, let's say I'm using the rightmost darkest character in const density, can I make that character alone blue for example?
Thank you.
EDIT: After the answer given below, I have added in the code like so:
const darkest = density[density.length-1]
const c = density.charAt(charIndex)
if (c == ' ') {
asciiImage += ' '
} else {
asciiImage += c;
}
if (c === darkest) {
asciiImage += `<span class='blue'>${c}</span>`
}
which now looks like this: https://imgur.com/a/dbqgCCa
I think the issue must be because it's adding c twice right?
Technically no, you can't change the color of a specific character, but you can wrap individual characters with an element (preferrably a span) that can be targeted with css.
// references the darkest character in the list
const darkest = density[density.length - 1]
// if the current character is the darkest character, wrap it in a span with a class of 'blue.'
if(c === ' ') {
asciiImage += '&nsbc;'
}
else if (c === darkest) {
asciiImage += `<span class='blue'>${c}</span>`
}
else {
asciiImage += c
}
And in your css, just color the characters blue
.blue {
color: blue;
}

Vis JS Timeline - Freeze horizontal time axis when vertically scrolling

I'm using the following options in Vis JS Timeline to produce a horizontal axis at the top of the timeline with time labels:
orientation: {
axis: 'both'
},
The horizontal axis looks like this:
My timeline has many rows, so the user needs to vertically scroll down the page to see everything. The problem is that the horizontal axis at the top does not stay in view when scrolling down the page.
Question: How can I freeze the horizontal axis at the top so that the time labels stay in view when scrolling down?
The following code snippet, or jsfiddle.net/nj1647tb, is my timeline:
const seed = '11';
Math.seedrandom(seed);
const nGroups = 40;
const maxSubGroups = 2;
const maxItemsPerSubGroup = 1;
const metaEventCount = 2;
const itemLengthScale = 200;
let now = moment().minutes(0).seconds(0).milliseconds(0);
var groupCount = 12;
var itemCount = 70;
var tcCrashProbability = 0.2;
function randInt(min, max) {
return Math.round(min + Math.random() * (max - min));
}
function getStartEnd(earliestStart) {
if (earliestStart === undefined) {
earliestStart = 0;
}
let startAdd = earliestStart + Math.random() * 200;
let length = Math.random() * itemLengthScale;
let endAdd = startAdd + length;
return {
startAdd: startAdd,
endAdd: endAdd
}
}
const stackTrace = `Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 756, in urlopen
method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
File "/usr/local/lib/python3.6/site-packages/urllib3/util/retry.py", line 532, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/usr/local/lib/python3.6/site-packages/urllib3/packages/six.py", line 769, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 706, in urlopen
chunked=chunked,
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 445, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 440, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib64/python3.6/http/client.py", line 1346, in getresponse
response.begin()
File "/usr/lib64/python3.6/http/client.py", line 307, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python3.6/http/client.py", line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/lib64/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
File "/usr/lib64/python3.6/ssl.py", line 971, in recv_into
`;
// create a data set with groups
var group_names = [];
var groups = new vis.DataSet();
for (let i = 0; i < nGroups; i++) {
group_names.push('GROUP_' + i);
groups.add({
id: group_names[i],
content: group_names[i]
});
}
// add meta group
groups.add({
id: -1,
content: ' '
});
// create a dataset with items
let items = new vis.DataSet();
for (let i = 0; i < nGroups; i++) {
let nSubGroups = randInt(1, maxSubGroups);
//console.log('group='+i+' nSubGroups='+nSubGroups);
let lastStartAdd = 0;
for (let sg = 0; sg < nSubGroups; sg++) {
let start_end = getStartEnd(lastStartAdd);
let start = now.clone().add(start_end['startAdd'], 'hours');
let end = now.clone().add(start_end['endAdd'], 'hours');
let itemID = 'G' + i + '_S' + sg + '_item';
let subgroupID = 'G' + i + '_S' + sg;
let subgroupOrder = sg;
let newItem = {
id: itemID,
group: group_names[i],
subgroup: subgroupID,
subgroupOrder: subgroupOrder,
content: 'ITEM_DU_' + 'G' + i + '_S' + sg,
start: start,
end: end,
title: 'ITEM_DU_' + 'G' + i + '_S' + sg
};
//console.log(group_names[i] + ', ' + 'S' + sg + ', ' +start_end['startAdd'] + ', ' + start_end['endAdd']);
items.add(newItem);
lastStartAdd = start_end['startAdd'];
// random crashes
if(Math.random() <= tcCrashProbability) {
let crashStart = now.clone().add(randInt(start_end['startAdd'], start_end['endAdd']), 'hours');
let newCrashItem = {
id: 'crash_' + itemID,
group: group_names[i],
subgroup: subgroupID,
subgroupOrder: subgroupOrder,
content: 'Crash',
start: crashStart,
type: 'box',
className: 'timeline-tc-crash',
title: '<pre>' + stackTrace + '</pre>'
};
items.add(newCrashItem);
}
}
}
// generate some meta events
for (let i = 0; i < metaEventCount; i++) {
let start = now.clone().add(Math.random() * 200, 'hours');
items.add({
id: 'M' + i,
group: -1,
content: 'Crash',
title: '<pre>' + stackTrace + '</pre>',
className: 'timeline-event-crash',
start: start,
type: 'box'
});
}
// create visualization
var container = document.getElementById('visualization');
var options = {
groupOrder: 'content',
stack: false,
stackSubgroups: true,
orientation: {
axis: 'both'
},
showCurrentTime: false
};
var timeline = new vis.Timeline(container);
timeline.setOptions(options);
timeline.setGroups(groups);
timeline.setItems(items);
#visualization {
box-sizing: border-box;
width: 100%;
height: 300px;
}
.timeline-event-crash {
background-color: red !important;
border-color: darkred !important;
color: white !important;
font-family: monospace;
box-shadow: 0 0 10px gray;
}
.timeline-tc-crash {
color: red !important;
border-color: red !important;
background-color: #F4BBB5 !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.3.10/seedrandom.min.js"></script>
<link href="https://visjs.github.io/vis-timeline/styles/vis-timeline-graph2d.min.css" rel="stylesheet" />
<script src="https://visjs.github.io/vis-timeline/standalone/umd/vis-timeline-graph2d.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<html>
<head>
<title>Timeline</title>
</head>
<body>
<div id="visualization"></div>
</body>
</html>
I don't know if you ever tried this, but when i am investigating the issue, when my mouse is over the left column i was able to scroll vertically. So not a fix from code side, but if you could not find a proper solution maybe you can add some guidance for your users like "if you want to see groups down below you should scroll when the mouse is over them".
P.S Though i did not deeply investigated this yet but i think this is an expected behavior from vis side, because as far as i have seen from their examples they do not have any option to horizontal scroll when mouse is over timeline

Create a different rectangle with the same size but with a different background color

Explanation:
Every rectangle needs to be shown with a different background color.
I created an array of colors and with the built rand function, active it on the rectangle.
But all rectangles appear in the same color.
var colors = ['#F44336 ', '#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E53935', '#D32F2F', '#C62828', '#B71C1C', '#FF8A80', '#FF5252', '#FF1744'];
var counter = 0;
function addRect() {
var rectobj = document.getElementsByClassName("Rectangles")[0];
var sections = "";
for (var i = 0; i < 15; i++) {
sections += "<section></section>";
}
rectobj.innerHTML = sections;
rectobj.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
}
addRect();
.Rectangles {
display: flex;
flex-wrap: wrap;
width: 1000px;
}
.Rectangles>section {
height: 350px;
width: 333px;
}
<main class="Rectangles"></main>
You are applying the background color to the .Rectangles class.
Try something like this:
var colors = ['#F44336 ', '#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E53935', '#D32F2F', '#C62828', '#B71C1C', '#FF8A80', '#FF5252', '#FF1744'];
var counter = 0;
function addRect() {
var rectobj = document.getElementsByClassName("Rectangles")[0];
var sections = "";
for (var i = 0; i < 15; i++) {
let bg = colors[Math.floor(Math.random() * colors.length)];
sections += "<section style='background:"+bg+"'></section>";
}
rectobj.innerHTML = sections;
//rectobj.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
}
addRect();
.Rectangles {
display: flex;
flex-wrap: wrap;
width: 1000px;
}
.Rectangles>section {
height: 350px;
width: 333px;
}
<main class="Rectangles">
</main>
If you need each block to have a different background color you could remove it from the array, but make sure you have enough colors in the array as blocks you will add:
var colors = ['#F44339 ', '#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E53935', '#D32F2F', '#C62828', '#B71C1C', '#FF8A80', '#FF5252', '#FF1744','#bF6734'];
var counter = 0;
function addRect() {
var rectobj = document.getElementsByClassName("Rectangles")[0];
var sections = "";
for (var i = 0; i < 15; i++) {
let bg = colors[Math.floor(Math.random() * colors.length)];
sections += "<section style='background:"+bg+"'></section>";
let index = colors.indexOf(bg);
if (index !== -1) {
colors.splice(index, 1);
}
}
rectobj.innerHTML = sections;
}
addRect();
.Rectangles {
display: flex;
flex-wrap: wrap;
width: 1000px;
}
.Rectangles>section {
height: 350px;
width: 333px;
}
<main class="Rectangles">
</main>
Try to change the function to be like that
function addRect() {
var rectobj = document.getElementsByClassName("Rectangles")[0];
var sections = "";
for (var i = 0; i < 15; i++) {
sections += "<section style='background-color: " + colors[Math.floor(Math.random() * colors.length)] + "'></section>";
}
rectobj.innerHTML = sections;
}
In your solution, you are assigning them directly to the main container, so, it's always the same

Unable to update image position in css using javascript

There are some runner(animation-image) in my program which move from position x to y when clicked on start button, i want to add a (reverse)button on completion that when clicked on that the image moves from y to x.
Here is the link of my js-fiddle: https://jsfiddle.net/o6egL4qr/
I have added the reverse button but when clicked on that the image doesn't move at all.
class raceManager {
raceCount = 0;
races = [];
addRace() {
var mainContainer = document.getElementById('mainContainer');
mainContainer.appendChild(document.createElement('br'));
var race = new raceClass(this.raceCount);
this.races.push(race);
this.raceCount++;
}
}
class raceClass {
runners = [];
count;
runnerCount = 0;
raceDiv = document.createElement('div');
raceNum = document.createElement('div');
startRaceButton = document.createElement('input');
addRunnerButton = document.createElement('input');
revRaceButton = document.createElement('input');
tableDiv = document.createElement('div');
tableNum = document.createElement('div');
startInterval;
startTime;
revStartTime;
reverseInterval;
constructor(number) {
// store the race no.
this.count = number;
// delcare the race div id
this.raceNum.id = 'raceNum' + this.count;
// delcare the table div id
this.tableNum.id = 'tableNum' + this.count;
// Add raceDiv to the race
document.getElementById('races').appendChild(this.raceDiv);
// Add tableDiv to the race
document.getElementById('tables').appendChild(this.tableDiv);
this.applyDivProperty();
this.initializeButtons();
}
applyDivProperty() {
// apply properties to the tableNum
this.tableNum.style.display = "inline-block";
// apply properties to the raceDiv
this.raceDiv.id = "Race" + this.count;
document.getElementById(this.raceDiv.id).classList.add("raceDivClass");
this.raceDiv.appendChild(this.raceNum);
document.getElementById(this.raceNum.id).innerHTML = '<p>Race: ' + this.count + '</p>';
// append the add race button
this.raceDiv.appendChild(this.addRunnerButton);
// apply properties to the tableDiv
this.tableDiv.id = "Table" + this.count;
document.getElementById(this.tableDiv.id).classList.add("tableClass");
this.tableDiv.appendChild(this.tableNum);
document.getElementById(this.tableNum.id).innerHTML = '<p>Table: ' + this.count + '</p>';
}
initializeButtons() {
// initialize add runner button
this.addRunnerButton.type = 'Button';
this.addRunnerButton.value = 'Add Runner';
this.addRunnerButton.id = 'AddRunner' + this.count;
this.addRunnerButton.onclick = this.addRunner.bind(this);
// initialize start race buttton
this.startRaceButton.type = 'Button';
this.startRaceButton.value = 'Start Race';
this.startRaceButton.id = "startRaceButton" + this.count;
this.startRaceButton.onclick = this.startRace.bind(this);
// initialize reverse race buttton
this.revRaceButton.type = 'Button';
this.revRaceButton.value = 'Reverse Race';
this.revRaceButton.id = "revRaceButton" + this.count;
this.revRaceButton.onclick = this.revRace.bind(this);
}
addRunner() {
var track = new Runner(this); //Initialize the runner object
this.runners.push(track); //Store the runner object in runners array of Race class
if (this.runnerCount > 0) {
// append the start race button
this.raceDiv.appendChild(this.startRaceButton);
}
this.runnerCount++;
}
startRace() {
this.startTime = Date.now();
this.startInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animate();
});
document.getElementById(this.startRaceButton.id).disabled = "true";
document.getElementById(this.addRunnerButton.id).disabled = "true";
}, 50);
}
stop() {
clearInterval(this.startInterval);
// append the start race button
this.raceDiv.appendChild(this.revRaceButton);
}
revRace() {
this.revStartTime = Date.now();
this.reverseInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animateReverse();
});
document.getElementById(this.revRaceButton.id).disabled = "true";
}, 50);
}
stopRev() {
clearInterval(this.reverseInterval);
}
}
class Runner {
count = 0;
parent;
track;
sprite;
timeTaken;
trackWidth;
element;
speed;
table;
printCount = 1;
stepCount = 1;
trackNum;
tbl;
lastStep;
constructor(race) {
// initialize the divs
this.parent = race;
this.track = document.createElement('div');
this.sprite = document.createElement('div');
this.table = document.createElement('table');
// assigns #id to table and track corresponding with parent div.
this.table.id = race.tableNum.id + '_Table_' + this.parent.runnerCount;
this.track.id = race.raceNum.id + '_Track_' + this.parent.runnerCount;
this.createUI();
this.timeTaken = ((Math.random() * 5) + 3);
this.speed = this.trackWidth / (this.timeTaken * 1000);
console.log(this.trackWidth, this.timeTaken);
console.log(this.timeTaken * 100);
}
createUI() {
this.count = this.parent.runnerCount;
this.createTable();
this.createTrack();
this.createSprite();
}
createTable() {
var parentDiv1 = document.getElementById(this.parent.tableNum.id);
parentDiv1.appendChild(this.table);
this.table.setAttribute = "border"
this.table.border = "1";
document.getElementById(this.table.id).classList.add("tableClass");
this.tbl = document.getElementById(this.table.id);
this.addRow("Track " + (this.count + 1), "");
this.addRow("Time", "Distance");
}
addCell(tr, val) {
var td = document.createElement('td');
td.innerHTML = val;
tr.appendChild(td)
}
addRow(val_1, val_2) {
var tr = document.createElement('tr');
this.addCell(tr, val_1);
this.addCell(tr, val_2);
this.tbl.appendChild(tr)
}
createTrack() {
var parentDiv = document.getElementById(this.parent.raceNum.id);
parentDiv.appendChild(this.track);
this.track.appendChild(this.sprite);
document.getElementById(this.track.id).classList.add("trackClass");
this.trackWidth = this.track.getBoundingClientRect().width;
}
createSprite() {
this.sprite.id = this.track.id + "_Runner";
document.getElementById(this.sprite.id).classList.add("spriteClass");
this.element = document.getElementById(this.sprite.id);
}
animate() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.startTime;
var diff = Math.floor(this.timeTaken * 100);
// step is position of sprite.
var step = timespent * this.speed;
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step > this.trackWidth - 23) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stop();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
// we use the ES6 template literal to insert the variable "position"
this.element.style.backgroundPosition = `${position}px 0px`;
}
animateReverse() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.revStartTime;
var diff = Math.floor(this.timeTaken * 100);
console.log(this.count + " position of step " + this.element.style.left);
while (this.stepCount < 2) {
this.lastStep = parseFloat(this.element.style.left);
this.stepCount++;
}
console.log(this.count + " this is lastStep " + this.lastStep);
// step is position of sprite.
var step = this.lastStep - (this.speed * timespent);
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step < 25) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stopRev();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
//var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
//this.element.style.backgroundPosition = position + 'px 0px';
}
}
manager = new raceManager();
#tableContainer {
float: left;
}
#addRaces {
text-align: center;
}
.raceDivClass {
margin: 1% auto;
width: 60%;
text-align: center;
border: 1px solid;
}
.tableClass {
text-align: center;
border: 1px solid;
margin: 5px;
float: left;
}
.trackClass {
background-color: black;
height: 30px;
width: 98%;
margin: 1%;
position: relative;
}
.spriteClass {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAAAeCAYAAADAZ1t9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASwSURBVGhD7Zq/axRBFMfv9u4MxATUSgsVm3QWigYbexuxUkiaKIqNoIUiwRSJoJLCxpSCaJoEYimo/4AgQVRIZxdBEIREYwzc5X74vndvlrm5mdnZ3dm9oPnAsDubu52Z93373pvNFQsJOXO9NUKHsU4vZPH90+IXPt/FA2kEmqbDTKcX8pza7K5I/vAtEJghge7zeSrwlDYbtYlmfWuILxWC8uBmUNoz/784wY4WaPRq9SGJcY+7Mt7GEOzUkB0pkGHi4Ci1K53TEK8h7tTE+pPywL6b3JXJQqBcQ7arQwR87AE34ElPUsPE1ZapODsErFHnnD7AfVWb9oylFYjVFcKoQuQC5kD55hB3Qxrbf17RYbHT+/fpCXGSOEmEaYcevofwhkRxXM0/VCi8azXr3+q1Xw8+LRxZ4cte4PneoHaQ2iVck0gVThVbyOhSRM9YOoFMyR9eW6KmLkAGYW6Vmjx47AViUfSkPC5V9p7nS23q1Z9zH+b33+KuF9iAOocUa0lcKFjubQJ2h51D5zbmIAVM9gc1mzgAE0kdFlFaq+JkQYQBV+FYOYoDGy9Tw3dgQ7QxnUBQUHxAtJfUhqllDhbWam4f525mJDCgMynufZFa13d6BILHsOeEjS6PUjMNtsRHFXgExI2V0PN6egiEkTzFMdlJgM/3zMd1H2Tzhjlqa53TLhLFbsvep9Cob70uFsuffbxJoHWZcq1A5CCZyDUZ7gtxotKDCsafdRHIZSFe9j9wBl1xoIJSuxhUVpIK5eB0JiILHo29EouDtVmLBF4IKjIbWOQkfzYVruENn+ESXFe+upBJeDMQVfWiyXQ5fFQV57oQLyLJL0VlsAfi06yJyhMuIOci7Efdqy0ENzxxonVFI22IY0NDHN1mykaX+nHAmKbw1qhtLLVaze8U1o6Jv9OmdaEYlI1lsLQGGVGwmMKbKZ8KXHIQxnUJn062CgVSFmQTRjySpr8n2nlb3lxTztl8W6+u3x0YOlylrpij1Vi0Hl3uxNx/U9MWIYSPtwZxclukSG2B4qreOTV+3skzBBgbuafVrJ0sVYbO8eUe4r5FMAgEbEnbSSC2l/p0grgRB1jHDGKqjt019kkwvoid4okS4D7O+Qji4MmxiQMonI2cGP/qYwMbt6LSAXFEzpCbyYaJcxuKBAwWJQ5EwATCTScLBeUhVGKRTIWBCgQsVYavcdcF8UZEnVveYPwXfIwNBMJCdF/GNeEZCFnahMzX1A0dgEi6MJALigP1SyiMCdu9wZH7sZBzkGpM5zcBljAZGdNPX964UAhKt0vlwbN8SQs2p/Xq2lTSfzU4hvK0OUily4b0PV1etI4Z+SbBFYMBrIPjO1QuT1N+GedLbVC1FYM9Hyk31fgScHYYE5JhD1Dz/r+fKPoqEJAMILAa1VRaU+HwaPnZwBR3vWJwJCDCUSonsKERKHJMrwLFAYbSbUwRyujanawMZfBikPXTEzvCgKhXPZmhe+/W2ZCuTWXpxQbgyWGFmhGILLb8p6V/AmnKa+Qd3783cCDz0JaGvgmEX4jyaRu8W6N8NM/dPGlvvvk8T5ye2r7mIIQ5PEl5/pyXc4FzIeOLZOMWCn8Bh1eBvOSZzIIAAAAASUVORK5CYII=');
position: absolute;
height: 30px;
width: 25px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="mainContainer">
<div id="addRaces">
<input type="Button" value="Add Race" onclick="manager.addRace()">
</div>
<div id="races">
</div>
<br>
</div>
<div id="tableContainer">
<div id="tables"></div>
</div>
</body>
</html>
I expect it to move from y to x after clicking the reverse button, but it is not moving.
When you run the reverse function the elements are no longer referencing the dom elements.
I am actually not sure why that is, maybe someone else can chime in.
Anyway, this will fix your problem:
Replace this.element.style.left = step + 'px';
With: document.getElementById(this.element.id).style.left = step + 'px';

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.

Categories

Resources