I've created a simple list from 0 to 10,000, where each li has a style type of upper-roman, a random background color as well as a child abbr to display hexadecimal string of the color.
When running the program I the list style changes from upper-roman to decimal after index 4000.
Can anyone explain to me what's happening here?
NOTE: Running the test takes a few seconds.
$(document).ready(readyHandler);
function readyHandler()
{
var $list = $("#MyList");
for (let i = 0; i < 10000; i++)
{
$list.append("<li><abbr title=\"\">Auto Insert " + i + "</abbr></li>");
}
colors = [];
for (let i = 0; i < $list.children().length; i++)
{
colors.push(getRandomColor());
}
$list.children().each(listItemsHandler);
}
function listItemsHandler(index, item)
{
var $target = $(item);
var color = colors[index];
$target.css("background-color", color);
$target.find("abbr").attr("title", color);
}
function getRandomColor()
{
var color = "#";
for (var i = 0; i < 3; i++)
{
var part = Math.round(Math.random() * 255).toString(16);
color += (part.length > 1) ? part : "0" + part;
}
return color;
}
#MyList
{
list-style-type: upper-roman;
margin-left: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id = "MyList"></ol>
At 4000, roman numerals begin to include the over-line which doesn't have an ASCII representation for display in plain text. For example, 4000 is IV with a line over the top. For this reason, there is no way for browser renderers to represent the numeral in char form as a <li> bullet.
The only way to represent this would be with an ADDITIONAL css property overline.
In short, it is not possible to represent numerals over 3999 as bullet items.
Related
I have a function that returns a random color. I push these colors into an array. I don't want the colors to be repeated in the array. So I did this:
$scope.getRandomColor = function getRandomColor(arrayToCheckIfAlreadyContains) {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
//check if array contains the generated color
if(arrayToCheckIfAlreadyContains.indexOf(color) >= 0){
let nonRepeatColor = $scope.getRandomColor(arrayToCheckIfAlreadyContains);
console.log("color repeated", color, arrayToCheckIfAlreadyContains);
return nonRepeatColor;
}
return color;
}
But I don't know if this is efficient or will even work for sure. Also, it would be great if the colors are distinguishable. Sometimes I get colors that are almost same. How do I make sure that doesn't happen.
hsl can help you produce distinguishable colors. Try this.
function makeColor(colorNum, colors){
if (colors < 1) colors = 1;
// defaults to one color - avoid divide by zero
return colorNum * (360 / colors) % 360;
}
// This could be length of your array.
var totalDIVs = 20;
var totalColors = totalDIVs;
for (var i = 0; i < totalDIVs; i++){
var element = document.createElement('div');
document.body.appendChild(element);
var color = "hsl( " + makeColor(i, totalColors) + ", 100%, 50% )";
element.style.backgroundColor = color;
element.innerHTML = color;
}
You might consider using hsl instead of hex notation - pick a number between 0 and 359 for the initial color, then select the other colors such that they're equidistant. For example:
function getColors(num) {
const initialColor = Math.floor(Math.random() * 360);
const increment = 360 / num;
const hsls = [];
for (let i = 0; i < num; i++) {
hsls.push(Math.round((initialColor + (i * increment)) % 360));
}
return hsls;
}
function displayNew() {
container.innerHTML = '';
const hsls = getColors(input.value);
hsls.forEach((hsl) => {
const div = container.appendChild(document.createElement('div'));
div.style.backgroundColor = 'hsl(' + hsl + ', 100%, 50%)';
});
}
#container > div {
height: 30px;
}
<input id="input" onkeyup="displayNew()" type="number">
<div id="container"></div>
From your code I don't quite understand what you are doing if the color is already in the array: do you want to pick another random color until you find one color that is not in the array?
Anyways, since your second goal (distinguishable colors), I guess you need some extra work: every time you pick a random color, you need to check its similarity against ALL the colors in the array!
Something like the following:
getRandomColor = function getRandomColor(arrayToCheckIfAlreadyContains) {
let colorFound = true;
let letters = '0123456789ABCDEF';
do {
colorFound = true;
var randomColor = '#';
for (var i = 0; i < 6; i++) {
randomColor += letters[Math.floor(Math.random() * 16)];
}
arrayToCheckIfAlreadyContains.some(color => {
if (distanceBetweenColor(color, randomColor) < TRESHOLD) {
/* Branch taken when randomColor is too similar
* to an already existing color. */
colorFound = false;
return true;
}
return false;
});
} while (!colorFound);
}
Now, how implementing distanceBetweenColor()? You should use Delta-E algorithm: I suggest you to read this answer in SO: https://stackoverflow.com/a/15189004/6070423
EDIT: Notice the use of some instead of forEach: doing this, you stop the iteration as soon as you find a color that is too similar.
I'm trying to animate a pattern matching algorithm. Depending on whether the characters of the text and pattern match or not the characters turn red or green and the pattern moves on. My problem is that the pattern moves along the text too fast not allowing enough time to show the pattern and text matching or not matching.
What would be the best way for me to try and achieve an animation where the algorithm checks if the characters match, updates the background colours then checks the next characters or moves the pattern along?
function animatePattern(boxWidth, shiftpos) {
$("#pattern_array").animate({left: boxWidth * shiftpos});
}
function turnRed(x, y) {
$(x + y).animate({backgroundColor: "#db1a35"});
}
function turnWhite(x, y) {
$(x + y).animate({backgroundColor: "#fff"});
}
function turnGreen(x, y) {
$(x + y).animate({backgroundColor: "#30ad03"});
}
function straightforward(p, t) {
var i = 0, j = 0, k = 0;
var boxWidth = $('#text_array .panel').outerWidth(true);
while (j < t.length && k < p.length) {
if (t[j]==p[k]) {
//turn text green
turnGreen('#t', j);
//turn pattern green
turnGreen('#p', k);
//update counters to compare next characters in the pattern and text
j = j + 1;
k = k + 1;
} else {
//turn the unmatched pattern character red
turnRed('#p', k);
turnRed('#t', j);
//turn all pattern white
for (var m = 0; m < p.length; m++) {
turnWhite('#p', m);
}
//turn all text white
for (var m = 0; m < t.length; m++) {
turnWhite('#t', m);
}
//update countes to compare the next character of text with first character of pattern
i = i + 1;
j = i;
k = 0;
//move pattern on a mismatch
animatePattern(boxWidth, i);
}
}
}
jsfiddle Here you can see the animation running
You can use $.fx.speeds._default = 750; to slow down the animation, but what you are doing now seems to be queuing all the animations initially, so they are playing out of sync. What you need to do is use a setTimeout or setInterval and create a "tick" function that runs every x seconds that updates the elements.
Some example code:
var intervalms = 1000
var i = 0;
function tick() {
if (!(i < 10)) return;
console.log(i++);
setTimeout(tick, intervalms)
}
tick();
Or using intervals
var intervalms = 1000
var i = 0;
function tick() {
if (!(i < 10)) {
clearInterval(tickInterval);
return;
}
console.log(i++);
}
var tickInterval = setInterval(tick, intervalms);
I am working with jquery and upon the HTML document completing loading, I need to display a 10x10 rectangle of "#" characters in my div tag whose ID is "artArea". I cannot seem to figure it out. Any help would be wonderful!
Here is my current progress: I am not sure if my function (retangle) is completely wrong or if I am calling the function incorrectly. https://jsfiddle.net/7u1ao2d9/
You can try to find the width of the given # character. Here is the code used to find the dimensions of the # character and calculate the dimensions for the container. Be sure that the target div and the character calculating divs both have the same line height and font size. Be sure to put the #charWidth div out of sight.
$(document).ready(function() {
$('#charWidth').html('#');
var charWidth = $('#charWidth').width();
var charHeight = $('#charWidth').height();
var target = document.getElementById('target');
target.style.width = 10 * charWidth + 'px';
target.style.height = 10 * charHeight + 'px';
console.log(10 * charWidth);
console.log(10 * charHeight);
for (var i = 0; i != 100; i++) {
if ((i % 10) == 0) target.innerHTML += '<br>';
target.innerText += '#';
}
});
#charWidth {
position: absolute;
top: 5000000000000vh;
opacity: 0;
display: table;
/*be sure that it has the same line height and font size as your target div*/
font-size: 16px;
line-height: 16px;
}
#target {
font-size: 16px;
line-height: 16px;
white-space: pre-wrap;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="charWidth"></div>
<div id="target"></div>
Count up to 100 while inserting a line break every 10 counts. Use the function to generate the output and use it on any element you want.
function rectangle(){
var r = "";
//Go about 10x10=100 counts
for (var i = 1; i <= 100; i++){
if (i % 10 === 0) //Insert line break every 10 counts
r += "\n"
else
r += "#";
}
return r;
}
$('#artArea').val() = rectangle();
Also consider this typical script pattern
<html>
<head>
<script>
$(document).ready(...)
</script>
</head>
<body>
...
</body>
</html>
You can use Developer Tools to debug your script.
There are quite a few issues with your code. For one, it's not a great idea to stick the script tag that draws your "#" rectangle in the div where you want the rectangle to go. It is a much better practice to put the script tags with the rest of your script tags at the bottom of the document. In this case, since you're using jQuery, make sure you put the rectangle drawing script tag BELOW the script tag that loads the jQuery library.
Now if your script tag is in the right place, the following should work for you:
<script>
function drawRect(){
var rect = "";
for (var i = 0; i < 10; i +=1){
for (var j = 0; j < 10; j += 1){
rect += "#"
}
rect += "\n"
}
return rect;
}
document.getElementById("artArea").innerHTML = drawRect();
</script>
All the above function is doing is using nested for-loops to build up a string of text. For every one time the outer loop runs, the inner loop will run ten times, so the function uses the inner loop to add 10 "#"s to the string, then the outer loop adds one "\n" to the end of the the 10 "#"s. The "\n" is called a newline character and causes a line-break in the text. To make sure this line-break renders in your html, add the following code to your css file:
#artArea {
white-space: pre;
}
Once the nested loops finish running, we have a string that contains a 10x10 grid of "#"s. Now all that remains is to select the HTML element we want to display the grid and insert that string into it. That's what the document.querySelector("#artArea").innerHTML = drawRect(); line does.
It's not super-obvious from your question, but looking at your code, it appears that you want this rectangle function to be able to draw different grids composed of different characters, depending on user input. If that's the case, then you would want to grab the input and pass it in as an argument to your function, like so:
var rows= parseInt($("#numRows").val(), 10);
var cols= parseInt($("#numCols").val(), 10);
var char= ("#drawChar").val();
function drawRect(rows,cols,char){
var rect = "";
for (var i = 0; i < rows; i +=1){
for (var j = 0; j < cols; j += 1){
rect += char;
}
rect += "\n"
}
return rect;
}
drawRect(rows,cols,char);
Just be aware that writing the function this way opens the door to possible errors and even security lapses depending upon user input. For example, if the user doesn't put a number into the row or col fields, that will break the code. So if you go this route you need to do more error-checking, character escaping, etc.
This version creates a table made up of Rows x Cols cells, places a # (or whatever you set Char to) inside each cell, and leaves you with something you can modify by using id = r(row number)c(col number).
I placed this block inside the head of the document.
As others have suggested, there should be some kind of input validation to ensure people do not place an array of javascript code pieces or similar.
Style the table and cells to make your output do what you want.
<script type="text/javascript">
function rectangle()
{
/**
*
*/
var Rows = parseInt($("input#numRows").val(), 10);
var Cols = parseInt($("input#numCols").val(), 10);
var Char = $("input#drawChar").val());
var artArea = document.getElementById("artArea")
if (document.getElementById("artTable"))
{
// assuming we made it
artArea.removeChild(document.getElementById("artTable"))
}
var my_table = document.createElement("TABLE");
my_table.id = "artTable"
artArea.appendChild(my_table);
for (var i=0; i < Rows; i++)
{
var this_row = document.createElement("TR")
this_row.id = "r" + i;
for ( var j=0; j < Cols; j++)
{
var this_cell = document.createElement("TD");
this_cell.id = this_row.id + "c" + j;
var my_text = document.createTextNode(Char);
this_cell.appendChild(my_text);
this_row.appendChild(this_cell);
}
my_table.appendChild(this_row);
}
}
$( document ).ready(function() { rectangle(); });
</script>
Tried it on jsfiddle, but have not made a document.
Here's a one-liner, excluding the docready:
$(document).ready(
$('#artArea').html("#".repeat(10).concat("\n").repeat(10))
);
You'll want to, like #btwebste mentioned, use a white-space declaration to ensure that the newlines are rendered.
#artArea {
text-align: center;
white-space: pre;
}
https://jsfiddle.net/rgjy50e5/
I'm trying to make the colour different for certain letters (if found) in a string eg. the letter i. The search count is working I just can't figure out the changing html colour of the individual letter.
I know if it was a whole word then I could just use split strings, but can't figure out how to do it for a single letter. I've found some examples, one that I have tried is at the bottom that is not working either.
//getMsg is another function, which passes in a user inputted string
function searchMsg(getMsg) {
alert (getMsg);
var msgBoxObject = document.getElementById('msgBox');
var pos = getMsg.indexOf('i')
var txtToFind = (document.getElementById('txtToFind').value);
var count = 0;
while (pos !== -1){
count++;
pos = getMsg.indexOf('i', pos + 1);
document.writeln (+count);
msgBoxObject.innerHTML = (count);
}
getMsg = getMsg.replace('/i/g<span class="red">i</span>');
document.writeln (getMsg);
}
Edit; I've added in this, but can't get the loop to work correctly so it displays all instances of the letter found instead of just one: /*while (pos !== -1){
count++;
pos = getMsg.indexOf('i', pos + 1);
document.writeln (+count);
msgBoxObject.innerHTML = (count);
}
*/
var count = 0; // Count of target value
var i = 0; // Iterative counter
// Examine each element.
for(i=0; i<arr.length; i++)
{ if(arr[i] == targetValue)
count++;
}
return count;
}
searchIndex = txtMsg.indexOf(txtToFind);
if (searchIndex >=0 ) {
// Copy text from phrase up till the match.
matchPhrase = txtMsg.slice(0, searchIndex);
matchPhrase += '<font color="red">' + txtToFind + '</font>';
matchPhrase += txtMsg.slice(searchIndex + txtToFind.length);
} else {
matchPhrase = "No matches"
}
displayProcessedMsg(matchPhrase);
document.writeln(matchPhrase);
You either need to add the corresponding css for that class or change the tag like #john_Smith specified
Adding the CSS
span.red {
color: red;
}
Changing the tag
On your code replace this
getMsg = getMsg.replace('/i/g<span class="red">i</span>');
for
getMsg = getMsg.replace('/i/g<span style:"color:red">i</span>');
Some example of inline css
Some advice on color palettes
Try looking into d3 color scales(https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors) or apply a principle similar to incrementing an RGB value instead of using names of colors.
Hope this helps.
I want to generate a string of random letters say 10 letters from a-z one after the other i.e. the next letter should be displayed after the previous letter after a certain delay, later, I want to calculate the number of times each letter has been generated, unlike what I have done previously, i.e. I have taken a predefined array of letters and generated them accordingly.
Shorter way to generate such a string using String.fromCharCode:
for (var i = 0, letter; i < 10; i++) {
setTimeout(function() {
letter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
out.appendChild(document.createTextNode(letter)); // append somewhere
}, 2000 * i);
}
And complete demo covering all the problems in this question: http://jsfiddle.net/p8Pjq/
Use the setInterval method to run code at an interval. Set up an array for counting each character from the start, then you can count them when you create them instead of afterwards:
var text = '';
var chars = 'abcdefghijklmnopqrstuvwxyz';
var cnt = new Array(chars.length);
for (var i = 0; i < cnt.length; i++) cnt[i] = 0;
var handle = window.setInterval(function(){
var ch = Math.floor(Math.random() * chars.length);
cnt[ch]++;
text += chars.charAt(ch);
$('#display').text(text);
if (text.length == 20) {
window.clearInterval(handle);
// now all characrers are created and counted
}
}, 2000);
Demo: http://jsfiddle.net/R8rDH/
I am stealing this answer, but look here: Generate random string/characters in JavaScript
function makeid()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}