Can I update a jS variable's property dynamically from another variable? - javascript

I'm trying to update a property of a jS variable using the scroll velocity which I'm storing in another variable. This is my code thus far (scroll to the second code box as the first part works correctly):
jQuery( document ).ready(function() {
jQuery('main').attr('id', 'grained');
(function (window, doc) {
"use strict";
function grained(ele, opt) {
var element = null,
elementId = null,
selectorElement = null;
if (typeof ele === 'string') {
element = doc.getElementById(ele.split('#')[1]);
}
if (!element) {
console.error('Grained: cannot find the element with id ' + ele);
return;
} else {
elementId = element.id;
}
//set style for parent
if (element.style.position !== 'absolute') {
element.style.position = 'relative';
}
element.style.overflow = 'hidden';
var prefixes = ["", "-moz-", "-o-animation-", "-webkit-", "-ms-"];
//default option values
var options = {
animate: true,
patternWidth: 100,
patternHeight: 100,
grainOpacity: 0.1,
grainDensity: 1,
grainWidth: 1,
grainHeight: 1,
grainChaos: 0.5,
grainSpeed: 20
};
Object.keys(opt).forEach(function (key) {
options[key] = opt[key];
});
var generateNoise = function () {
var canvas = doc.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = options.patternWidth;
canvas.height = options.patternHeight;
for (var w = 0; w < options.patternWidth; w += options.grainDensity) {
for (var h = 0; h < options.patternHeight; h += options.grainDensity) {
var rgb = Math.random() * 256 | 0;
ctx.fillStyle = 'rgba(' + [rgb, rgb, rgb, options.grainOpacity].join() + ')';
ctx.fillRect(w, h, options.grainWidth, options.grainHeight);
}
}
return canvas.toDataURL('image/png');
};
function addCSSRule(sheet, selector, rules, index) {
var ins = '';
if (selector.length) {
ins = selector + "{" + rules + "}";
} else {
ins = rules;
}
if ("insertRule" in sheet) {
sheet.insertRule(ins, index);
} else if ("addRule" in sheet) {
sheet.addRule(selector, rules, index);
}
}
var noise = generateNoise();
var animation = '',
keyFrames = ['0%:-10%,10%', '10%:-25%,0%', '20%:-30%,10%', '30%:-30%,30%', '40%::-20%,20%', '50%:-15%,10%', '60%:-20%,20%', '70%:-5%,20%', '80%:-25%,5%', '90%:-30%,25%', '100%:-10%,10%'];
var pre = prefixes.length;
while (pre--) {
animation += '#' + prefixes[pre] + 'keyframes grained{';
for (var key = 0; key < keyFrames.length; key++) {
var keyVal = keyFrames[key].split(':');
animation += keyVal[0] + '{';
animation += prefixes[pre] + 'transform:translate(' + keyVal[1] + ');';
animation += '}';
}
animation += '}';
}
//add animation keyframe
var animationAdded = doc.getElementById('grained-animation');
if (animationAdded) {
animationAdded.parentElement.removeChild(animationAdded);
}
var style = doc.createElement("style");
style.type = "text/css";
style.id = 'grained-animation';
style.innerHTML = animation;
doc.body.appendChild(style);
//add custimozed style
var styleAdded = doc.getElementById('grained-animation-' + elementId);
if (styleAdded) {
styleAdded.parentElement.removeChild(styleAdded);
}
style = doc.createElement("style");
style.type = "text/css";
style.id = 'grained-animation-' + elementId;
doc.body.appendChild(style);
var rule = 'background-image: url(' + noise + ');';
rule += 'position: absolute;content: "";height: 300%;width: 300%;left: -100%;top: -100%;';
pre = prefixes.length;
if (options.animate) {
while (pre--) {
rule += prefixes[pre] + 'animation-name:grained;';
rule += prefixes[pre] + 'animation-iteration-count: infinite;';
rule += prefixes[pre] + 'animation-duration: ' + options.grainChaos + 's;';
rule += prefixes[pre] + 'animation-timing-function: steps(' +options.grainSpeed + ', end);';
}
}
//selecter element to add grains
selectorElement = '#' + elementId + '::before';
addCSSRule(style.sheet, selectorElement, rule);
}
window.grained = grained;
//END
})(window, document);
// Here down is the important part //
var grainOptions = {
animate: true,
patternWidth: 100,
patternHeight: 100,
grainOpacity: 0.04,
grainDensity: 1,
grainWidth: 1,
grainHeight: 1
};
grained('#grained', grainOptions);
document.querySelector("body").addEventListener("wheel", scrollGlitch);
function scrollGlitch(event) {
var y = event.deltaY;
var scaleY = y;
var divider = 100;
var sum = scaleY / divider;
console.log(sum);
}
});
From this I am getting 2 things which I need:
the property value of grainOpacity;
the scroll velocity as stored in the variable sum (which is divided by 100 to make the values the right scale i.e 0.01 - 0.1;
What I need to do now is update the grainOpacity property of the grainOptions variable with the value of the sum variable. Is this possible? How would I achieve this, I read about Bracket/Dot notations but can't tell if this is the right way.

You can take any object field reference using dot like
grainOptions.grainOpacity
Then you can redefine field value as using let variables.
Update your scrollGlitch function:
function scrollGlitch(event) {
var y = event.deltaY;
var scaleY = y;
var divider = 100;
var sum = scaleY / divider;
grainOptions.grainOpacity = sum;
}
Note. In JS you can take Object fields' value with 2 ways:
With saving reference on field to update it's own value. Ex:
grainOptions.grainOpacity.
Only for take value. Ex:
grainOptions['grainOpacity']

Related

Problem with dynamic size array in javascript

I am trying to develop my own game engine running on JavaScript for text adventure games. It's more of a personal project than actually trying to go anywhere with it, but none the less, I am having fun.
The problem I am currently getting is Uncaught TypeError: optionGroups[(num + 1)] is undefined from my console, as well as a reference to line 97 in filereader.js. I believe that this is because of how I am defining the array, or trying to use it, but I am also unsure of the "correct" way to do so.
My filereader.js file
var raw;
function initFileReader(){
document.getElementById('fileInput').addEventListener('change', handleFileSelect, false);
}
function handleFileSelect(event){
const reader = new FileReader()
reader.onload = handleFileLoad;
reader.readAsText(event.target.files[0])
}
function handleFileLoad(event){
//console.log(event.target.result);
raw = event.target.result;
//All save files should be marked with MSF somewhere in the file.
if (!raw.includes("MSF")){
alert("Not a Save File");
}
else{
/*
* SYNTAX FOR SAVE FILE
* ===========================================================
* startupMessage = <T><T>
* optionText = <"0"><"0"> where 0 is the index of the entry.
* optionAddition = <'0'><'0'> where 0 is the index of the entry.
* optionGroups = <:0:>1,2<:0:> where 0 is the index of the group, and 1,2 is the list of the entries separated by commas
* ===========================================================
* Overrides are done by the last conflicting thing in the file being chosen.
* Important sections of the text are denoted by <!><!> and will show up as blue text.
*/
var buffer = raw;
//Pulling out the startup message.
buffer = buffer.substring(buffer.search("<T>") + 3);
startupMessage = buffer.substring(0, buffer.search("<T>"));
buffer = buffer.substring(buffer.search("<T>") + 3);
buffer = buffer.trim();
startupMessage = startupMessage.replace(/<!>/g, "<a class=\"important\">");
startupMessage = startupMessage.replace(/<\/!>/g, "</a>");
bodyText += startupMessage;
buffer = buffer.replace(/<!>/g, "<a class=\"important\">");
buffer = buffer.replace(/<\/!>/g, "</a>");
//Start segment parting
//console.log(buffer);
while(buffer != "" || buffer){
switch(buffer.charAt(1)){
case '\"':
//console.log("optionText");
var num = Number(buffer.substring(2).substring(0, buffer.substring(2).search("\"")));
//console.log(num);
buffer = buffer.substring(3).substring(buffer.substring(3).search(">") + 1);
//console.log(buffer);
var temp = buffer.substring(0, buffer.search("<\"" + num + "\">"));
//console.log(temp);
buffer = buffer.substring(temp.length + ("<\"" + num + "\">").length + 2);
//console.log(buffer);
//console.log(""+ num + " : " + temp);
optionText[num] = temp;
break;
case '\'':
//console.log("optionAddition");
var num = Number(buffer.substring(2).substring(0, buffer.substring(2).search("\'")));
//console.log(num);
buffer = buffer.substring(3).substring(buffer.substring(3).search(">") + 1);
//console.log(buffer);
var temp = buffer.substring(0, buffer.search("<\'" + num + "\'>"));
//console.log(temp);
buffer = buffer.substring(temp.length + ("<\'" + num + "\'>").length + 2);
//console.log(buffer);
//console.log(""+ num + " : " + temp);
optionAddition[num] = temp;
break;
case ':':
//console.log("optionGroups");
var num = Number(buffer.substring(2).substring(0, buffer.substring(2).search(":")));
//console.log(num);
buffer = buffer.substring(3).substring(buffer.substring(3).search(">") + 1);
//console.log(buffer);
var temp = buffer.substring(0, buffer.search("<:" + num + ":>"));
//console.log(temp);
buffer = buffer.substring(temp.length + ("<:" + num + ":>").length + 2);
//console.log(buffer);
//console.log(""+ num + " : " + temp);
let nums = temp.split(",");
console.log(Number(nums[0]));
console.log(optionGroups);
for(let i = 0; i < nums.length; ++i){
optionGroups[num+1][i] = Number(nums[i]);
++i;
}
console.log(optionGroups);
break;
}
}
var el = document.getElementById("gameSelectionWrapper");
var opacity = 1.0;
var fade = setInterval(() =>{
if(opacity <= 0){
el.parentNode.removeChild(el);
clearTimeout(fade);
}
else {
opacity = opacity - 0.02;
el.style.opacity = opacity;
}
}, 30/1000);
createSelections(0);
}
}
My index.js file
var bodyText = "";
var prevBodyText = bodyText;
var optionText = [];
var optionAddition = [];
var currentOptionGroup = 0;
var optionGroups = [];
var startupMessage = "";
function startup(){
initFileReader();
mainLoop();
}
function mainLoop(){
setInterval(()=>{
updateText();
prevBodyText = bodyText;
}, 30/1000);
}
function updateText(){
if(prevBodyText != bodyText){
let body = document.getElementById("bodyTextWrapper");
body.innerHTML = bodyText;
body.scrollTop = body.scrollHeight;
console.log(">> Updated Body Text");
}
}
function selectionHandler(flag){
for(let i = 0; i < optionGroups[currentOptionGroup].length; ++i){
removeOption(optionGroups[currentOptionGroup][i]);
}
createSelections(flag+1);
currentOptionGroup = flag + 1;
bodyText += "<br><br>" + optionAddition[flag];
}
function removeOption(optionNum){
var el = document.getElementById("option" + optionNum);
if(el != null){
var opacity = 1.0;
var fade = setInterval(() =>{
if(opacity <= 0){
el.parentNode.removeChild(el);
clearTimeout(fade);
}
else {
opacity = opacity - 0.05;
el.style.opacity = opacity;
}
}, 30/1000);
}
}
function createSelections(setNumber){
for(var e in optionGroups[setNumber]){
createOption(optionGroups[setNumber][e]);
}
}
function createOption(optionNum){
console.log("Making option");
var div = document.createElement("DIV");
div.className = "selection";
div.setAttribute("onclick", "selectionHandler("+optionNum+");");
div.id = "option" + optionNum;
div.innerHTML = ">> " + optionText[optionNum];
div.style.opacity = 0.0;
document.getElementById("selectionWrapper").appendChild(div);
var opacity = 0;
setTimeout(() => {
var fade = setInterval(() => {
if(opacity >= 1){
clearTimeout(fade);
}
else {
opacity = opacity + 0.05;
div.style.opacity = opacity;
}
}, 30/1000);
}, 400);
}
My sample save file
MSF
<T>Hello and welcome. <!>Please</!> press <!>Start</!> to begin.<T>
<"0">Start<"0">
<'0'>You have started the game.<'0'>
<:0:>1,2<:0:>
<"1">Go Left<"1">
<'1'>Heading left.<'1'>
<"2">Go Right<"2">
<'2'>Heading right.<'2'>
Please let me know if you need to see anything else, I would really appreciate any feedback on this one.

I wrote a closure to add draggable elements to a map. I expected the enclosre to preserve values. It doesn't. Why not?

I want to annotate a route on a map using vanilla javascript. To that end, I have a canvas element, a draw routine to 'connect' divs to points on the map, a closure to construct small divs, and another closure to make the divs draggable, so they can be more conveniently positioned over the map. In both closures, I'm having what I think is the same problem.
js & HTML to show the problem with the make-it-draggable closure, makeDraggable, are below. The outermost function declares a variable, dragThis. The dragstart handler assigns it value. onDragOver and onDrop use it. The debugger says dragThis is in the same makeDraggable closure at every use. I expected this approach to simplify the overall structure and efficiency of the code.
The problem: When the drag and drop handlers fire, dragThis doesn't have the value assigned in dragStart. Why?(???) (In fact, the value in the drag and drop handlers seems to be the id of the element in the first call to makedraggable by test.)
Associated questions:
I use the setData/getData methods of the dataTransfer object. For the life of me, i don't understand the first argument of those functions, 'format'. It seems to have nothing whatever to do with 'format' (save that it changes 'text' to 'text/plain' internally), and everything to do with identifying a datum. The value of 'format' can be just about any string. From the W3: *The API does not enforce the use of MIME types; other values can be used as well.* 'name' would seem to be a more appropriate, um, name. Am i missing something? Shouldn't ducks be called ducks? This hardly seems deserving of a separate question, but I'm curious and don't know how else to ask.
MDN says the event object's pageX, pageY "...include any portion of the page not currently visible." They do not seem to include non-visible portions of scrolled elements, so that seems false. What am i missing? (And does my pageXY function correctly calculate a position that does take those invisible bits properly into account? It seems to work, but my example may be too simple.)
Firefox and fiddle seem happy with my code. Chrome, though, at drop time in placeEl, thinks 'el' in 'el.style.left =...' is null: TypeError: Cannot read property 'style' of null.... Nonetheless, it is happy with the next line, and magically goes on to properly position the div.
I put the code at https://jsfiddle.net/HerbX/g7zv1ok2/1/ Maybe its still there. I've hardwired illustrative divs into the html.
Apparently having referenced the fiddle, I need to put the code here as well:
var MYSTUFF = {
makeDraggable:function(el, elChart) {
var dragThis = el;
var ops = {capture:true, useCapture:true};
el.draggable = true;
el.addEventListener('dragstart', onDragStart, ops);
console.log("dragstart listener added to " + el.id);
if (elChart.dataset.dragover === undefined) {
elChart.addEventListener('dragover', onDragOver, ops);
elChart.addEventListener('drop', onDrop, ops);
elChart.dataset.dragover = 'dragover';
console.log("dragover listener added to " + elChart.id);
}
return el;
function onDragStart(ev) {
var clickXY;
dragThis = ev.target;
clickXY = MYSTUFF.pageXY(ev);
ev.dataTransfer.clearData();
ev.dataTransfer.setData('text/plain',toStr(ev.target.id, ev.target.offsetLeft, ev.target.offsetTop, clickXY.x, clickXY.y));
ev.dataTransfer.setData('foo', ev.target.id);
console.log("dragStart: dragThis.id is " + dragThis.id + ", dT = " + ev.dataTransfer.getData('text/plain'));
}
function onDragOver(ev){
var pos; // new (style.top, style.left)
var canvasid; // canvas, if px, py exist
var params, el;
var foo;
ev.preventDefault();
params = ev.dataTransfer.getData('text/plain').split(';')
foo = ev.dataTransfer.getData('foo');
el = document.getElementById(params[0]);
pos = placeEl(ev, el); // Reposition el by delta(mouse)
console.log("onDragOver: dragThis.id = " + dragThis.id + '; foo = ' + foo);
}
function onDrop(ev) {
var canvasTemp, canvasid, ctx;
var dT, params;
var el, els;
ev.preventDefault();
dT = ev.dataTransfer.getData('text/plain');
params = dT.split(';');
console.log("onDrop event: dragThis.id is " + dragThis.id + ", dT is " + dT);
el = document.getElementById(params[0]);
placeEl(ev,el); //Reposition el, ignore return.
}
function toStr() {
// arguments => ;-delimited string. Args must be scalar numbers.
var delim='';
var s = "";
for (var i = 0; i < arguments.length; i++) {
if (isNaN(arguments[i])) {
s += delim + arguments[i];
} else {
s += delim + arguments[i].toFixed(1);
}
delim = ";";
}
return s;
}
function placeEl(ev,el) {
/* Re-position el by delta(mouse position) */
var params;
var dx, dy;
var pos;
var cursorXY;
params = ev.dataTransfer.getData('text/plain').split(';');
cursorXY = MYSTUFF.pageXY(ev);
dx = cursorXY.x - parseFloat(params[3]);
dy = cursorXY.y - parseFloat(params[4]);
pos = {x:parseFloat(params[1]) + dx, y:parseFloat(params[2]) + dy};
el.style.left = pos.x + 'px';
el.style.top = pos.y + 'px';
return pos;
}
},
reportXY: function(ev) {
let x, y, abs, sAbs;
let msg = document.getElementById('msg');
let el = ev.srcElement;
let id = el.id;
if (id === "") id = el.tagName;
x = event.pageX.toFixed(0);
y = event.pageY.toFixed(0);
abs = MYSTUFF.pageXY(ev);
sAbs = "(" + abs.x + "," + abs.y + ")";
msg.innerText = "In " + id + ", cursor # Page XY: (" + x + "," + y +"). Including scrolls, cursor # " + sAbs;
},
pageXY:function(ev) {
let x = ev.pageX;
let y = ev.pageY;
let scrollX, scrollY, tagName, el;
el = ev.srcElement;
tagName = el.tagName;
scrollX = el.scrollLeft;
scrollY = el.scrollTop;
while (tagName !== 'HTML') {
el = el.parentElement;
tagName = el.tagName;
scrollX += el.scrollLeft;
scrollY += el.scrollTop;
}
return {x:x+scrollX, y:y+scrollY}
}
}
/* test1() only tests makeDraggable. It uses elements hardwired into the HTML.*/
function test1() {
var elChart = document.getElementById('chartPosRef');
var div = document.getElementById('div-0');
MYSTUFF.makeDraggable(div, elChart);
div = document.getElementById('div-1');
MYSTUFF.makeDraggable(div,elChart);
div = document.getElementById('div-2');
MYSTUFF.makeDraggable(div,elChart);
div = document.getElementById('div-3');
MYSTUFF.makeDraggable(div,elChart);
}
window.addEventListener('DOMContentLoaded', (event) => {
window.addEventListener('mousemove', MYSTUFF.reportXY);
test1();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>connected</title>
<style>
.small {
position:absolute;
width:7em;
background-color:#e6ffe6;
}
.red {
background-color:red;
}
</style>
<script src="js/Q1.js"></script>
</head>
<body>
<div id="chartCtnr" style="text-align:center;">
<div id="chartResz" class="resizeable" style="width:500px;height:500px;display:inline-block">
<div id="chartScroll" style="overflow:auto;height:100%;width:100%;display:inline-block;">
<div id="chartPosRef" class="freezer" style="position:relative">
<canvas id="connectedCanvas" class="red" width="3718" height="2614" title="Track">This to draw the connected track</canvas>
<div id='div-0' class='small' style='top:100px;left:100px;'>this is div-0</div>
<div id='div-1' class='small' style='top:120px;left:080px;'>this is div-1</div>
<div id='div-2' class='small' style='top:140px;left:100px;'>this is div-2</div>
<div id='div-3' class='small' style='top:160px;left:080px;'>this is div-3</div>
</div>
</div>
</div>
</div>
<div id='msg'>this is a message</div>
</body>
</html>
The problem was the 'closure' wasn't a closure. Now it is, after reading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures a little more carefully, and this works. Note that dragStart (and a couple of other variables) are defined at the top of 'dragger' (as, in effect, are makeDraggable, onDragStart and so on.)
Next to do (but not here cuz i doubt that anyone cares...) is to add variables needed to draw lines connecting the divs to points on the map (non-existent here). Most are closure variables, and setting them will add little to no overhead to the drag operation - largely the point of this exercise.
setData('foo', target.id) remains because I'd still like to know why documentation refers to that first argument as a 'format'.
var MYSTUFF = {
dragger: function() {
var dragThis; // element being dragged
var clickXY; // click-position relative to ULC of scrolled area
var elStartXY; // Initial position of dragThis rel to ULC of scrolled area.
var canvas;
return makeDraggable;
function makeDraggable (el, elChart) {
var ops = {capture:true, useCapture:true};
dragThis = el;
el.draggable = true;
el.addEventListener('dragstart', onDragStart, ops);
if (elChart.dataset.dragover === undefined) {
elChart.addEventListener('dragover', onDragOver, ops);
elChart.addEventListener('drop', onDrop, ops);
elChart.dataset.dragover = 'dragover';
}
return el;
}
function onDragStart(ev) {
dragThis = ev.target;
clickXY = MYSTUFF.pageXY(ev);
elStartXY = {x:ev.target.offsetLeft, y:ev.target.offsetTop};
ev.dataTransfer.setData('foo', ev.target.id);
}
function onDragOver(ev){
var pos; // new (style.top, style.left)
var canvasid; // canvas, if px, py exist
var params, el;
var foo;
ev.preventDefault();
pos = placeEl(ev,dragThis);
}
function onDrop(ev) {
var canvasTemp, canvasid, ctx;
var dT, params;
var el, els;
ev.preventDefault();
placeEl(ev,dragThis);
}
function toStr() {
// arguments => ;-delimited string. Args must be scalar numbers.
var delim='';
var s = "";
for (var i = 0; i < arguments.length; i++) {
if (isNaN(arguments[i])) {
s += delim + arguments[i];
} else {
s += delim + arguments[i].toFixed(1);
}
delim = ";";
}
return s;
}
function placeEl(ev,el) {
/* Re-position el by delta(mouse position) */
var params;
var dx, dy;
var pos;
var cursorXY;
cursorXY = MYSTUFF.pageXY(ev);
dx = cursorXY.x - clickXY.x;
dy = cursorXY.y - clickXY.y;
pos = {x:elStartXY.x + dx, y:elStartXY.y + dy};
el.style.left = pos.x + 'px';
el.style.top = pos.y + 'px';
return pos;
}
}, // end 'dragger'
reportXY: function(ev) {
let x, y, abs, sAbs;
let msg = document.getElementById('msg');
let el = ev.srcElement;
let id = el.id;
if (id === "") id = el.tagName;
x = event.pageX.toFixed(0);
y = event.pageY.toFixed(0);
abs = MYSTUFF.pageXY(ev);
sAbs = "(" + abs.x + "," + abs.y + ")";
msg.innerText = "In " + id + ", cursor # Page XY: (" + x + "," + y +"). Including scrolls, cursor # " + sAbs;
},
pageXY:function(ev) {
let x = ev.pageX;
let y = ev.pageY;
let scrollX, scrollY, tagName, el;
el = ev.srcElement;
tagName = el.tagName;
scrollX = el.scrollLeft;
scrollY = el.scrollTop;
while (tagName !== 'HTML') {
el = el.parentElement;
tagName = el.tagName;
scrollX += el.scrollLeft;
scrollY += el.scrollTop;
}
return {x:x+scrollX, y:y+scrollY}
}
}
/* test1() only tests makeDraggable. It uses elements hardwired into the HTML.*/
function test1() {
md = MYSTUFF.dragger();
var elChart = document.getElementById('chartPosRef');
var div = document.getElementById('div-0');
md(div, elChart);
div = document.getElementById('div-1');
md(div, elChart);
div = document.getElementById('div-2');
md(div, elChart);
div = document.getElementById('div-3');
md(div, elChart);
}
window.addEventListener('DOMContentLoaded', (event) => {
window.addEventListener('mousemove', MYSTUFF.reportXY);
test1();
});

Adding onclick event in JavaScript with parameters

I'm trying to make a dropdown to display the results of a request given what the user writes in a field.
The problem I'm encountering is that when I try to add an onclick event to each item in the dropdown, only the last one acts like expected.
The dropdown is a section and I try to include sections in it.
Here is the dropdown :
<section id="projectDrop">
</section>
Here is the code :
var j = 0;
var tmp;
for (var i=0;((i<infos.projects.length) && (i<5));i++)
{
if (infos.projects[i].name.toLowerCase().match(projectName.value.toLowerCase()))
{
projectDrop.innerHTML += '<section id="project' + j + '">' + infos.projects[i].name + '</section>';
tmp = document.getElementById('project' + j);
projectDrop.style.height = (j+1)*20 + 'px';
tmp.style.top = j*20 + 'px';
tmp.style.height = '20 px';
tmp.style.width = '100%';
tmp.style.color = 'rgb(0, 0, 145)';
tmp.style.textAlign = 'center';
tmp.style.cursor = 'pointer';
tmp.style.zIndex = 5;
tmp.onclick = function(name, key)
{
return function()
{
return insertProject(name, key);
};
} (infos.projects[i].name, infos.projects[i].key);
++j;
}
}
The result is visually as I expected, I can see the dropdown with all my projects listed and a pointer while hovering etc...
But only the last project is clickable and trigger the "insertProject" function while the other do nothing.
If someone could help me solve that !
You need to store the key somewhere. Take a look at the solution below, I have used the data-key attribute on the <section> to store the key.
Also note how I have changed the code to create the element object and assign its properties, instead of building a raw string of HTML. The problem with building HTML as a string is you have to worry about escaping quotes, whereas this way you don't.
var j = 0;
var tmp;
for (var i=0;((i<infos.projects.length) && (i<5));i++)
{
if (infos.projects[i].name.toLowerCase().match(projectName.value.toLowerCase()))
{
tmp = document.createElement('section');
tmp.id = "project" + j;
tmp.setAttribute('data-key', infos.projects[i].key);
tmp.innerHTML = infos.projects[i].name;
projectDrop.style.height = (j+1)*20 + 'px';
tmp.style.top = j*20 + 'px';
tmp.style.height = '20 px';
tmp.style.width = '100%';
tmp.style.color = 'rgb(0, 0, 145)';
tmp.style.textAlign = 'center';
tmp.style.cursor = 'pointer';
tmp.style.zIndex = 5;
tmp.onclick = function(){
insertProject(this.innerHTML, this.getAttribute('data-key'));
};
projectDrop.appendChild(tmp);
++j;
}
}
Change:
tmp.onclick = function(name, key)
{
return function()
{
return insertProject(name, key);
};
} (infos.projects[i].name, infos.projects[i].key);
to
tmp.onclick = function(j){
return function(name, key)
{
return function()
{
return insertProject(name, key);
};
} (infos.projects[j].name, infos.projects[j].key);
}(i)

Trouble getting setInterval and setTimeout to work

This uses Raphaeljs to draw a single chord from an array:
function createChordStruct(key, string, shape) {
var string = string.toUpperCase();
var position = positions[string][key];
var struct = chord_shapes[shape];
return {
name: key + struct.name,
chord: struct.chord,
position: position,
position_text: struct.position_text,
bars: struct.bars
}
}
function createChordElement(chord_struct) {
var chordbox = $('<div>').addClass('chord');
var chordcanvas = $('<div>');
var chordname = $('<div>').addClass('chordname');
chordbox.append(chordcanvas);
chordbox.append(chordname);
chordname.append(chord_struct.name);
var paper = Raphael(chordcanvas[0], 150, 140);
var chord = new ChordBox(paper, 30, 30);
chord.setChord(
chord_struct.chord,
chord_struct.position,
chord_struct.bars,
chord_struct.position_text);
chord.draw();
return chordbox;
}
function createSectionElement(section_struct) {
var section = $('<div>').addClass('section');
var section_title = $('<div>').addClass('title');
var section_desc = $('<div>').addClass('description');
section.append(section_title);
section.append(section_desc);
section_title.append(section_struct.section);
section_desc.append(section_struct.description);
return section;
}
And this takes each chord created from the array and puts them in a new div called "chordscroller":
function c_i() {
var randomholder = 'id_' + (Math.floor(Math.random() * 100005) + 1);
var randomId = 'id_' + (Math.floor(Math.random() * 100005) + 1);
$(function () {
$('#sortable').append($('<li id ="' + randomholder + '" class="chordbox"><span id="i" class="scale">C - I</span><span id="' + randomId + '" class=" even scrollpane chordscroller"></span></li>').sortable( "refresh" ))
});
function c_one() {
var container = $("#" + randomId + "");
var column = null;
var column = _.shuffle(c_1);
for (var i = 0; i < column.length; ++i) {
var section_struct = column[i];
var section = createSectionElement(section_struct);
for (var j = 0; j < section_struct.chords.length; ++j) {
section.append(createChordElement(section_struct.chords[j]));
}
container.append(section);
}
}
$(function() { c_one() });
}
The problem is it draws all the chords at the same time and it takes forever. I've tried every combination of setTimeout and setInterval I could think of but I keep running into errors.
Can anybody tell from this code how to get the chords to be drawn one at a time instead of all at once?
Finally figured it out (using a plugin called doTimeout):
$.doTimeout( 1, function() {
chord.setChord(
chord_struct.chord,
chord_struct.position,
chord_struct.bars,
chord_struct.position_text);
chord.draw();
});

JavaScript "null or not an object" error

I'm running the JavaScript below to place horizontal scrolling text on the banner of my website. It works in one server but not another. I get the following error:
Error: 'this.mqo' is null or not an object
JavaScript:
function start() {
new mq('m1');
/* new mq('m2');
*/
mqRotate(mqr); // must come last
}
window.onload = start;
// Continuous Text Marquee
// permission to use this Javascript on your web page is granted
// provided that all of the code below in this script (including these
// comments) is used without any alteration
function objWidth(obj) {
if (obj.offsetWidth) return obj.offsetWidth;
if (obj.clip) return obj.clip.width;
return 0;
}
var mqr = [];
function mq(id) {
this.mqo = document.getElementById(id);
var wid = objWidth(this.mqo.getElementsByTagName('span')[0]) + 5;
var fulwid = objWidth(this.mqo);
var txt = this.mqo.getElementsByTagName('span')[0].innerHTML;
this.mqo.innerHTML = '';
var heit = this.mqo.style.height;
this.mqo.onmouseout = function () {
mqRotate(mqr);
};
this.mqo.onmouseover = function () {
clearTimeout(mqr[0].TO);
};
this.mqo.ary = [];
var maxw = Math.ceil(fulwid / wid) + 1;
for (var i = 0; i < maxw; i++) {
this.mqo.ary[i] = document.createElement('div');
this.mqo.ary[i].innerHTML = txt;
this.mqo.ary[i].style.position = 'absolute';
this.mqo.ary[i].style.left = (wid * i) + 'px';
this.mqo.ary[i].style.width = wid + 'px';
this.mqo.ary[i].style.height = heit;
this.mqo.appendChild(this.mqo.ary[i]);
}
mqr.push(this.mqo);
}
function mqRotate(mqr) {
if (!mqr) return;
for (var j = mqr.length - 1; j > -1; j--) {
maxa = mqr[j].ary.length;
for (var i = 0; i < maxa; i++) {
var x = mqr[j].ary[i].style;
x.left = (parseInt(x.left, 10) - 1) + 'px';
}
var y = mqr[j].ary[0].style;
if (parseInt(y.left, 10) + parseInt(y.width, 10) < 0) {
var z = mqr[j].ary.shift();
z.style.left = (parseInt(z.style.left) + parseInt(z.style.width) * maxa) + 'px';
mqr[j].ary.push(z);
}
}
mqr[0].TO = setTimeout('mqRotate(mqr)', 10);
}
The reason is most likely that there is no element with the id "m1". Place this line first in the start function to diagnose this:
alert(document.getElementById('m1'));
If it shows "[Object]" (or similar), the element exists and it's some other problem, but if it shows "undefined" it means that there is no such element in the page.

Categories