Nodejs Game using too much cpu/ram - node.js

I am making a Nodejs Multiplayer game.
PROBLEM: After a period of time, around a few seconds, the latency between the server to client skyrockets. Not just a little. I have gotten up to 60 seconds of delay!!!! My server has 24GB of RAM and 8 CPU cores so this really surprised me. Also, the latency between the client and server is perfectly normal so I have to believe something is wrong with my code. This problem has been super annoying when I try to play it.
What I have tried:
So, I have a temporary solution for this that DELAYS the problem, but doesn't remove it. When I set perMessageDeflate up to the defaults on the documentation, I have like 2x the play time before I have lag.
I have done internet speed tests on my server. Both upload and download speed are above 1000 Mbps
I have done websocket server tests and I can achieve pretty good results(around 30,000 to 40,000 messages per second)
WHAT HELP WITH THE PROBLEM:
1.) perMessageDeflate set to documentation
const io = require("socket.io")(httpServer, {
perMessageDeflate: {
threshold: 2048, // defaults to 1024
zlibDeflateOptions: {
chunkSize: 8 * 1024, // defaults to 16 * 1024
},
zlibInflateOptions: {
windowBits: 14, // defaults to 15
memLevel: 7, // defaults to 8
},
clientNoContextTakeover: true, // defaults to negotiated value.
serverNoContextTakeover: true, // defaults to negotiated value.
serverMaxWindowBits: 10, // defaults to negotiated value.
concurrencyLimit: 20, // defaults to 10
}
});
2.) Lowering the fps the server runs
I want it to run at 120 fps(well not frames, more like updates) so ups, but I can only manage around 30 so I can play for a longer period of time.
CODE:
My code is kinda long(10000+ lines. I have too much free time) so I have removed unnecessary stuff:
Server:
Socket code:
io.on('connection', socket => {
sockets.push(socket);
socket.on('message', async function(msg) { // async is for other stuff I use my server for
if (socket.username == undefined) {
socket.username = JSON.parse(msg).username;
if (JSON.parse(msg).task != 'auth') {
if (bans.includes(socket.username)) {
socket.disconnect();
}
}
}
var data = JSON.parse(msg);
if (data.operation === 'multiplayer') { // I use my websocket server for other stuff then multiplayer things, but they dont have any performance issues.
if (data.task == 'tag') {
if (socket.room == undefined) {
socket.room = 'main';
if (tagRooms[0] == 0) {
socket.tagRoom = 0;
servers.tag[socket.room] = new HostTag();
servers.tag[socket.room].control(socket.room);
servers.tag[socket.room].sockets.push(socket);
tagRooms[0]++;
} else {
socket.tagRoom = 0;
servers.tag[socket.room].sockets.push(socket);
tagRooms[0]++;
}
} else {
if (data.event == 'joinerupdate') {
servers.tag[socket.room].joinerupdate(data)
}
if (data.event == 'joinerjoin') {
servers.tag[socket.room].joinerjoin(data);
}
}
} else if (data.task == 'pixel-tanks') {
if (data.gamemode == 'ffa') {
if (socket.room == undefined) {
socket.gamemode = 'ffa';
if (JSON.parse(msg).mode == 'quick-join') {
var l = 0, ip;
while (l < pvpRooms.length) {
if (pvpRooms[l] < 5) {
ip = 'quick-join' + l;
pvpRooms[l] += 1;
socket.pvpRoom = l;
socket.room = ip;
if (pvpRooms[l] == 1) {
console.log('[MULTI] => New FFA server created ' + ip);
servers.tanks.ffa[ip] = new HostTanks(ip, 'FFA');
console.log(util.inspect(servers));
}
servers.tanks.ffa[ip].sockets.push(socket);
l = pvpRooms.length;
}
l++;
}
if (socket.pvpRoom == undefined) {
socket.disconnect();
sockets = sockets.filter(s => s !== socket);
return;
}
} else {
if (servers.tanks.ffa[data.room] == undefined) {
if (data.room == undefined) {
console.log(util.inspect(data.room));
return;
}
console.log('[MULTI] => New FFA room created ' + data.room);
servers.tanks.ffa[data.room] = new HostTanks(data.room, 'FFA');
}
servers.tanks.ffa[data.room].sockets.push(socket);
socket.room = data.room;
}
} else {
if (data.event == 'joinerupdate') {
servers.tanks.ffa[socket.room].joinerupdate(data);
}
if (data.event == 'joinerjoin') {
servers.tanks.ffa[socket.room].joinerjoin(data.data);
}
}
}
// I have other gamemodes but they all have the same problem and similar code so i will just have ffa
}
}
});
socket.on('disconnect', function() {
if (socket.room != undefined && socket.tagRoom == undefined) {
servers.tanks[socket.gamemode][socket.room].disconnect(socket.username);
} else if (socket.room != undefined && socket.tagRoom != undefined) {
servers.tag[socket.room].disconnect(socket.username);
}
if (socket.pvpRoom != undefined) {
pvpRooms[socket.pvpRoom] -= 1;
}
if (socket.duelRoom != undefined) {
duelRooms[socket.duelRoom] -= 1;
}
if (socket.tdmRoom != undefined) {
tdmRooms[socket.tdmRoom] -= 1;
}
if (socket.defenseRoom != undefined) {
defenseRooms[socket.tdmRoom] -= 1;
}
if (socket.tagRoom != undefined) {
tagRooms[socket.tagRoom] -= 1;
}
sockets = sockets.filter(s => s !== socket);
});
});
This is the actual rendering of the game(on server). It's what runs the game.
class HostTanks {
constructor(channelname, gamemode) {
this.spawn = {
x: 0,
y: 0,
}
this.channelname = channelname;
this.gamemode = gamemode;
this.gamestate = 0; // 0 -> Waiting for Players, 1 -> Game started!
this.s = [];
this.b = [];
this.pt = [];
this.ai = [];
this.scaffolding = [];
this.sockets = [];
this.i = [];
this.t = [];
if (this.gamemode == 'DUELS' || this.gamemode == 'RAID' || this.gamemode == 'DEFENSE' || this.gamemode == 'TDM') {
this.i.push(setInterval(function(host) {
host.gameRunner(host);
}, 30, this));
}
... game running and stuff
}
gameRunner(host) {
// runs the game // not really important
}
joinerupdate(data) {
var tank = data.data;
var l = 0;
while (l < this.pt.length) {
if (this.pt[l].username == tank.username) {
// Apply updates to server //
// This part is where it sends the data back to the player
var m = 0;
while (m<this.sockets.length) {
if (this.sockets[m].username == this.pt[l].username) {
var gameMessage;
if (!this.gameMessage) {
if (this.pt[l].ded) {
gameMessage = 'Back in '+new String(new Date().getTime() - this.pt[l].dedTime.getTime());
} else {
var kills = this.pt[l].kills;
gameMessage = 'Kills: ' + kills;
}
} else {
gameMessage = this.gameMessage;
}
this.sockets[m].emit('message', JSON.stringify({
sendTime: new Date().toISOString(),
event: 'hostupdate',
tanks: this.pt,
blocks: this.b,
scaffolding: this.scaffolding,
bullets: this.s,
gameMessage: gameMessage,
}, replacer));
}
m++;
} // Send update as soon as joiner sends data
}
l++;
}
}
joinerjoin(data) { //done
// registers a new tank to the server
// pt = playertanks, teamData = team core hp and team playertanks
var tank = data;
if (this.gamemode == 'FFA') {
var l = 0;
while (l<this.sockets.length) {
if (this.sockets[l].username == tank.username) {
this.sockets[l].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'x',
value: this.spawn.x,
key2: 'y',
value2: this.spawn.y,
}
}));
}
l++;
}
} else if (this.gamemode == 'DUELS') {
var l = 0;
while (l < this.sockets.length) {
if (this.sockets[l].username == tank.username) {
if (this.pt.length == 0) {
this.sockets[l].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'x',
value: 0,
key2: 'y',
value2: 0,
}
}));
} else if (this.pt.length == 1) {
this.sockets[l].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'x',
value: 1460,
key2: 'y',
value2: 1460,
}
}));
}
}
l++;
}
} else if (this.gamemode == 'DEFENSE') {
var l = 0;
while (l < this.sockets.length) {
if (this.sockets[l].username == tank.username) {
this.sockets[l].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'team',
value: 'Players',
}
}));
}
l++;
}
} else if (this.gamemode == 'TDM') {
tank.team = 'lobby';
tank.damagedRecent = false;
this.pt.push(tank);
if (this.pt.length == 6) {
var l = 0, blue = [], red = [];
while (l<this.pt.length) {
var canBlue, canRed;
if (blue.length != 3) {
canBlue = true;
} else {
canBlue = false;
}
if (red.length != 3) {
canRed = true;
} else {
canRed = false;
}
if (canBlue && canRed) {
if (Math.random() < 0.5) {
blue.push(this.pt[l]);
this.pt[l].team = 'blue';
} else {
red.push(this.pt[l]);
this.pt[l].team = 'red';
}
} else {
if (canBlue) {
blue.push(this.pt[l]);
this.pt[l].team = 'blue';
} else if (canRed) {
red.push(this.pt[l]);
this.pt[l].team = 'red';
}
}
l++;
}
this.teams = {
blue: blue,
red: red,
}
this.gamestate = 1;
levelReader([' ',' # # ',' # # # #### # ',' # ## ### ### # ',' # ',' # ',' # ##### #### ##### # ',' # # ',' # # ','### ######### ############ ',' # # # ',' # # # ',' # ## ## ## ##### ',' # # # ',' ######## # # # ',' # # # ######## ',' # # # ',' ##### ## ## ## # ',' # # # ',' # # # ',' ############ ######### ###',' # # ',' # # ',' # ##### #### ##### # ',' # ',' # ',' # ### ### # ',' # #### # # ## # ',' # # ',' '], true, this);
this.count = 10;
this.gameMessage = 'Game Starting in '+this.count;
this.countdown = setInterval(function() {
var l = 0;
while (l<this.pt.length) {
if (this.pt[l].team == 'blue') {
var q = 0;
while (q<this.sockets.length) {
if (this.pt[l].username == this.sockets[q].username) {
this.sockets[q].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'x',
value: 0,
key: 'y',
value: 730,
}
}))
}
q++;
}
} else if (this.pt[l].team == 'red') {
var q = 0;
while (q<this.sockets.length) {
if (this.pt[l].username == this.sockets[q].username) {
this.sockets[q].emit('message', JSON.stringify({
event: 'override',
data: {
key: 'x',
value: 1460,
key2: 'y',
value2: 730,
}
}))
}
q++;
}
}
l++;
}
this.count -= 1;
this.gameMessage = 'Game Starting in '+this.count;
if (this.count == 0) {
this.gamestate = 2;
this.gameMessage = 'FIGHT'
clearInterval(this.countdown);
}
}.bind(this), 1000);
}
return;
}
tank.damagedRecent = false;
this.pt.push(tank);
}
disconnect(username) { // done?
if (this.gamemode == 'DUELS') {
this.gamestate = 0; // If someone leaves, prevent game crashing by going back to waiting for opponent.
}
var l = 0;
while (l < this.pt.length) {
if (this.pt[l].username == username) {
var q = 0;
while (q<this.pt[l].t.length) {
clearTimeout(this.pt[l].t[q]);
q++;
}
var q = 0;
while (q<this.pt[l].i.length) {
clearInterval(this.pt[l].i[q]);
q++;
}
clearTimeout(this.pt[l].inactiveTimer);
clearTimeout(this.pt[l].inactiveTimer2);
this.pt.splice(l, 1);
}
l++;
}
var l = 0,
gamemode;
while (l < this.sockets.length) {
if (this.sockets[l].username == username) {
gamemode = this.sockets[l].gamemode;
this.sockets.splice(l, 1);
}
l++;
}
if (this.sockets.length == 0) {
var l = 0;
while (l < this.i) {
clearInterval(this.i[l]);
l++;
}
servers.tanks[gamemode][this.channelname] = undefined;
console.log('[MULTI] => Server shutdown - ' + this.channelname);
delete this;
}
}
}
Here is a brief description of what the code does
Client makes request to server to join a room
If empty the server creates a new one
A room is a HostTanks object
Client joins server and it socket is registered
Client sends joinerjoin event and the socket.io server redirects it to the appropriate HostTanks object where the data is processed by the game
Client sends joinerupdate events at a rate determined by the client.
I have noticed it lags more the more fps I try to run this at
The lag doesn't occur instantly but happens after a few seconds
permessagedeflate(on the socket.io server) set to true actually improve performance for me
Socket.io server redirects the data to the HostTanks object and the game processes it
The HostTanks object sends back data immediately after applying updates(to provide best ping to players)
Gameplay continues until client disconnects where socket server tell the HostTanks that the client has left and the game ends.

Related

Other product variant is disabled and I can not select it for 2 products (JS)

I am a coding beginner and I am building a store. My problem is that I have a product in different fabrics. Now I can only select one fabric type and the other is disabled and I can not select no matter what I do. Perfect would be if I select the fabric type, the associated products are displayed.
That what i mean
/*============================================================================
Dynamic variant availability
- To disable, set dynamicVariantsEnable to false in theme.liquid
==============================================================================*/
setCurrentVariantAvailability: function(variant) {
var valuesToEnable = {
option1: [],
option2: [],
option3: []
};
// Disable all options to start
this.disableVariantGroup($(selectors.formContainer, this.$container).find('.variant-input-wrap'));
// Combine all available variants
var availableVariants = this.variantsObject.filter(function(el) {
if (variant.id === el.id) {
return false;
}
// Option 1
if (variant.option2 === el.option2 && variant.option3 === el.option3) {
return true;
}
// Option 2
if (variant.option1 === el.option1 && variant.option3 === el.option3) {
return true;
}
// Option 3
if (variant.option1 === el.option1 && variant.option2 === el.option2) {
return true;
}
});
// IE11 can't handle shortform of {variant} so extra step is needed
var variantObject = {
variant: variant
};
availableVariants = Object.assign({}, variantObject, availableVariants);
// Loop through each available variant to gather variant values
for (var property in availableVariants) {
if (availableVariants.hasOwnProperty(property)) {
var item = availableVariants[property];
var option1 = item.option1;
var option2 = item.option2;
var option3 = item.option3;
if (option1) {
if (valuesToEnable.option1.indexOf(option1) === -1) {
valuesToEnable.option1.push(option1);
}
}
if (option2) {
if (valuesToEnable.option2.indexOf(option2) === -1) {
valuesToEnable.option2.push(option2);
}
}
if (option3) {
if (valuesToEnable.option3.indexOf(option3) === -1) {
valuesToEnable.option3.push(option3);
}
}
}
}
// Have values to enable, separated by option index
if (valuesToEnable.option1.length) {
this.enableVariantOptionByValue(valuesToEnable.option1, 'option1');
}
if (valuesToEnable.option2.length) {
this.enableVariantOptionByValue(valuesToEnable.option2, 'option2');
}
if (valuesToEnable.option3.length) {
this.enableVariantOptionByValue(valuesToEnable.option3, 'option3');
}
},
updateVariantAvailability: function(evt, value, index) {
if (value && index) {
var newVal = value;
var optionIndex = index;
} else {
var $el = $(evt.currentTarget);
var newVal = $el.val() ? $el.val() : evt.currentTarget.value;
var optionIndex = $el.data('index');
}
var variants = this.variantsObject.filter(function(el) {
return el[optionIndex] === newVal;
});
// Disable all buttons/dropdown options that aren't the current index
$(selectors.formContainer, this.$container).find('.variant-input-wrap').each(function(index, el) {
var $group = $(el);
var currentOptionIndex = $group.data('index');
if (currentOptionIndex !== optionIndex) {
// Disable all options as a starting point
this.disableVariantGroup($group);
// Loop through legit available options and enable
for (var i = 0; i < variants.length; i++) {
this.enableVariantOption($group, variants[i][currentOptionIndex]);
}
}
}.bind(this));
},
disableVariantGroup: function($group) {
if (this.settings.variantType === 'dropdown') {
$group.find('option').prop('disabled', true)
} else {
$group.find('input').prop('disabled', true);
$group.find('label').toggleClass('disabled', true);
}
},
enableVariantOptionByValue: function(array, index) {
var $group = $(selectors.formContainer, this.$container).find('.variant-input-wrap[data-index="'+ index +'"]');
for (var i = 0; i < array.length; i++) {
this.enableVariantOption($group, array[i]);
}
},
enableVariantOption: function($group, value) {
// Selecting by value so escape it
value = value.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g,'\\$1');
if (this.settings.variantType === 'dropdown') {
$group.find('option[value="'+ value +'"]').prop('disabled', false);
} else {
var $buttonGroup = $group.find('.variant-input[data-value="'+ value +'"]');
$buttonGroup.find('input').prop('disabled', false);
$buttonGroup.find('label').toggleClass('disabled', false);
}
},
Have already tried various things, but not come to the desired result, even disabling the function ensures that everything is displayed and also clickable.
I hope you can help me.
Best Regards

chrome.browserAction, disabling Icon

I am attempting to disable or enable my chrome extension based on the matches of the content scripts, but I think there is a better way. Below is my code. Seems like what I am attempting to accomplish could be achieved by chrome.declarativeContent.onPageChanged but that does not seem to fire consistently.
const IsMatch = (tab, matches) => {
if (tab ==undefined && tab == null && tab.url == undefined){
return false;
}
for(var ctr = 0; ctr < matches.length ; ctr ++){
var match = matches[ctr].substring(0, matches[ctr].length - 1);
if (tab.url.startsWith(match) ) {
return true;
}
}
return false;
}
const updateIcon = tabId => {
chrome.browserAction.disable();
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
var contentScripts = chrome.runtime.getManifest().content_scripts;
for(var i = 0; i < contentScripts.length ; i ++){
var contentScript = contentScripts[i];
if ( IsMatch(tabs[0], contentScript.matches) ) {
chrome.browserAction.enable();
console.log('chrome.tabs.query');
console.log(tabs[0]);
return;
}
}
});
};
chrome.tabs.onUpdated.addListener(updateIcon);
After the changes recommended by #wOxxOm I am now in a race condition here is the updated code
browser.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'enableIcon') {
console.log(sender.tab.id + ' ' + request.message);
chrome.browserAction.setIcon({tabId: sender.tab.id, path: 'icon-16.png'});
browser.browserAction.enable();
}
return true;
});
browser.tabs.onUpdated.addListener(function(tabId) {
console.log(tabId + ' disableIcon');
chrome.browserAction.setIcon({tabId: tabId, path: 'icon-16-Disabled.png'});
chrome.browserAction.disable();
});
Here is the ouput:
- 6: backgroundIcon.js:31 39 disableIcon
- 1: backgroundIcon.js:22 39 enableIcon
- 2: backgroundIcon.js:31 39 disableIcon

Code inject via Content Script gets removed

I am creating a Chrome Extension that would draw an image above tag showing Flash content. I have written the content script in my "contentscript.js" file which does nothing but simply inserts another script file "backgroundscript.js" into page's body via a script tag.
The code works on few of sites having flash videos and shows the image right above the Flash Player window but on other sites it does not show up. Also on few it shows up for a fraction of a second and then gets disappeared.
Below is my manifest file:
{
"name": "My First Chrome Extension",
"version": "1.0.0.0",
"description": "Tag videos from websites with a single click!",
"icons": { "16":"application_16.png","48":"application_48.png","128":"application_128.png" },
"homepage_url": "http://www.myurl.com",
"page_action":{
"default_icon":{
"19":"application_19.png",
"38":"application_38.png"
},
"default_title":"VDownloader browser plugin"
},
"content_scripts": [ { "js": [ "contentscript.js" ], "matches": [ "http://*/*" ], "run_at" : "document_end", "all_frames": true} ],
"plugins": [ { "path": "myplugin.dll", "public": true } ],
"manifest_version":2,
"minimum_chrome_version":"17",
"offline_enabled":true,
"permissions":["tabs","http://*/*", "https://*/*","contextMenus"],
"web_accessible_resources":["application.png","backgroundscript.js"]
}
Also I checked by inserting "debugger;" into my script and monitoring code execution via console; the script gets added at least once into the page body. Even in the cases where no image button is shown.
Is this some kind of anit-XSS control implemented on the the more advanced sites not showing my button?
I would really appreciate your help as I have been trying to get over this from past couple of weeks without success :(
EDIT:
Please see the content script below:
var s = document.createElement('script');
s.src = chrome.extension.getURL("backgroundscript.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
Target sites:
Does not show the button: http://www.metacafe.com
Shows the button for a moment: http://www.dailymotion.com
Shows the button correctly: http://www.myreviewalarm.com
Please take a look at backgroundscript.js content:
var vdDelayTimer;
var vdUpdateInterval;
var playerButtons;
embedPlugin();
function embedPlugin() {
var embed = document.createElement('embed');
embed.setAttribute('type', 'application/x-myplugin');
embed.setAttribute('id', 'myplugin');
embed.setAttribute('style', 'width:1px;height:1px;position:absolute;left:0px;top:0px;');
if(document.body!=null)
{
document.body.appendChild(embed);
}
testPlugin();
}
function testPlugin() {
var plugin = document.getElementById('vdPlugin');
if (plugin != null) {
playerButtons = [];
vdDelayTimer = setTimeout("appendButtons()", 2000);
}
else {
window.alert('Plugin does not exist!');
}
}
function updateButtons() {
for (i = 0; i < playerButtons.length; i += 2) {
updateButtonLocation(playerButtons[i], playerButtons[i + 1]);
}
}
function updateButtonLocation(player, button) {
var playerX = getX(player);
var playerY = getY(player);
var buttonHeight = 38;
var buttonWidth = 196;
var buttonX = playerX + player.offsetWidth - buttonWidth - 12;
var buttonY = playerY - buttonHeight + 1;
button.setAttribute('style', 'background-image: url(http://myurl.com/img/browser-download-button.png); width:' + buttonWidth + 'px;height:' + buttonHeight + 'px;position:absolute;left:' + buttonX + 'px;top:' + buttonY + 'px; cursor:pointer; cursor:hand;');
}
function appendButtons() {
debugger;
var objectTags = document.getElementsByTagName('object');
for (var i = 0; i < objectTags.length; i++) {
var objectTag = objectTags[i];
if ((objectTag.hasAttribute('classid') && objectTag.getAttribute('classid') == 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000')
|| (objectTag.hasAttribute('type') && objectTag.getAttribute('type') == 'application/x-shockwave-flash')) {
if (objectTag.offsetWidth >= 320 && objectTag.offsetHeight >= 240)
createButton(objectTag, getX(objectTag), getY(objectTag), objectTag.offsetWidth);
}
}
var embedTags = document.getElementsByTagName('embed');
for (var i = 0; i < embedTags.length; i++) {
try {
var embedTag = embedTags[i];
if (embedTag.hasAttribute('type') && embedTag.getAttribute('type') == 'application/x-shockwave-flash') {
if (embedTag.offsetWidth >= 320 && embedTag.offsetHeight >= 240)
createButton(embedTag, getX(embedTag), getY(embedTag), embedTag.offsetWidth);
}
}
catch (err) { }
}
var videoTags = document.getElementsByTagName('video');
for (var i = 0; i < videoTags.length; i++) {
try {
var videoTag = videoTags[i];
if (videoTag.hasAttribute('src')) {
if (videoTag.offsetWidth >= 320 && videoTag.offsetHeight >= 240)
createButton(videoTag, getX(videoTag), getY(videoTag), videoTag.offsetWidth);
}
}
catch (err) { }
}
vdUpdateInterval = setInterval("updateButtons();", 500);
}
function createButton(videoTag, playerX, playerY, playerWidth) {
debugger;
var buttonHeight = 38;
var buttonWidth = 196;
var buttonX = playerX + playerWidth - buttonWidth - 12;
var buttonY = playerY - buttonHeight + 1;
var vdPlugin = document.getElementById('vdPlugin');
var strLocation = window.location.toString();
// if (isSupported(strLocation)) {
var downloadButton = document.createElement('img');
downloadButton.setAttribute('title', 'Tag this video');
downloadButton.setAttribute('src', 'http://myurl.com/img/browser-download-button.png');
downloadButton.setAttribute('style', 'background-image: url(http://myurl.com/img/browser-download-button.png); width:' + buttonWidth + 'px;height:' + buttonHeight + 'px;position:absolute;left:' + buttonX + 'px;top:' + buttonY + 'px; cursor:pointer;cursor:hand;z-index:2147483647;');
downloadButton.setAttribute('onclick', 'javascript:document.getElementById(\'vdPlugin\').downloadNow(window.location.href);');
downloadButton.setAttribute('oncontextmenu', 'javascript:return false;');
document.body.appendChild(downloadButton);
playerButtons.push(videoTag, downloadButton);
// }
}
function getY(oElement) {
var iReturnValue = 0;
while (oElement != null) {
iReturnValue += oElement.offsetTop;
oElement = oElement.offsetParent;
}
return iReturnValue;
}
function getX(oElement) {
var iReturnValue = 0;
while (oElement != null) {
iReturnValue += oElement.offsetLeft;
oElement = oElement.offsetParent;
}
return iReturnValue;
}
function isSupported(url) {
var regLen = supportedSites.length;
var regEx;
var res = false;
try {
for (var i = 0; i < regLen && res == false; i++) {
regEx = new RegExp(supportedSites[i], "i");
res = regEx.test(url);
}
}
catch (ex) {
}
return res;
}

Rickshaw.Graph.RangeSlider TypeError: $(element).slider is not a function

I have this error:
TypeError: $(element).slider is not a function
with the following script:
Rickshaw.namespace('Rickshaw.Graph.RangeSlider');
Rickshaw.Graph.RangeSlider = function(args) {
var element = this.element = args.element;
var graph = this.graph = args.graph;
$( function() {
$(element).slider( {
range: true,
min: graph.dataDomain()[0],
max: graph.dataDomain()[1],
values: [
graph.dataDomain()[0],
graph.dataDomain()[1]
],
slide: function( event, ui ) {
graph.window.xMin = ui.values[0];
graph.window.xMax = ui.values[1];
graph.update();
// if we're at an extreme, stick there
if (graph.dataDomain()[0] == ui.values[0]) {
graph.window.xMin = undefined;
}
if (graph.dataDomain()[1] == ui.values[1]) {
graph.window.xMax = undefined;
}
}
} );
} );
$(element)[0].style.width = graph.width + 'px';
graph.onUpdate( function() {
var values = $(element).slider('option', 'values');
$(element).slider('option', 'min', graph.dataDomain()[0]);
$(element).slider('option', 'max', graph.dataDomain()[1]);
if (graph.window.xMin == undefined) {
values[0] = graph.dataDomain()[0];
}
if (graph.window.xMax == undefined) {
values[1] = graph.dataDomain()[1];
}
$(element).slider('option', 'values', values);
} );
};
From the following page:
https://github.com/shutterstock/rickshaw/blob/master/src/js/Rickshaw.Graph.RangeSlider.js
The javascript debugger show me this line: slide: function( event, ui ) {
Can you show me a way to resolve my problem. Thanks you!
You should import jqueryui before using the slider.
http://jqueryui.com/slider/

JQuery Dynatree - search node by name

I would like to start using Dynatree on my page, however I will probably need searching my tree by name. Do you know maybe how to do this?
I needed to have not only matching nodes, but also the whole paths to these nodes. I wrote this functionality and it works for me.
Modifications for library:
var clear = true;
DynaTreeNode.prototype.search = function(pattern){
if(pattern.length < 1 && !clear){
clear = true;
this.visit(function(node){
node.expand(true);
node.li.hidden = false;
node.expand(false);
});
} else if (pattern.length >= 1) {
clear = false;
this.visit(function(node){
node.expand(true);
node.li.hidden = false;
});
for (var i = 0; i < this.childList.length; i++){
var hide = {hide: false};
this.childList[i]._searchNode(pattern, hide);
}
}
},
DynaTreeNode.prototype._searchNode = function(pattern, hide){
if (this.childList){
// parent node
var hideNode = true;
for(var i = 0; i < this.childList.length; i++){
var hideChild = {hide: false};
this.childList[i]._searchNode(pattern, hideChild);
hideNode = hideNode && hideChild.hide;
}
if(hideNode && !this._isRightWithPattern(pattern)){
this._hideNode();
hide.hide = true;
} else {
hide.hide = false;
}
} else {
// leaf
if (!this._isRightWithPattern(pattern)){
this._hideNode();
hide.hide = true;
} else {
hide.hide = false;
}
}
},
DynaTreeNode.prototype._isRightWithPattern = function(pattern){
if((this.data.title.toLowerCase()).indexOf(pattern.toLowerCase()) >= 0){
return true;
}
return false;
},
DynaTreeNode.prototype._hideNode = function(){
if(this.li) {
this.li.hidden = true;
}
}
Use:
$("tree").dynatree("getRoot").search(pattern);
There is currently no search function, but you could use something like this (not tested)
var match = null;
tree.visit(function(node){
if(node.data.title === "foo"){
match = node;
return false; // stop traversal (if we are only interested in first match)
}
});
alert("Found " + match);
I've done it this way
<style>
span.occurance a.dynatree-title{background-color:#3AFF22;}
</style>
DynaTreeNode.prototype.find = function (needle) {
needle = (needle || '');
if (needle.length >= 1) {
var occurs = [];
this.visit(function (node) {
$(node.span).removeClass('occurance'); //remove pervious findings
if (node.data.title.indexOf(needle) != -1) {
occurs.push(node);
node._expandPath();
}
});
for (indx in occurs) { // mark findings
$(occurs[indx].span).addClass('occurance');
}
} else {
$('span.dynatree-node.occurance').removeClass('occurance');
}
},
DynaTreeNode.prototype._expandPath = function () {
var path = [],
node = this;
while (node = node.getParent()) {
path.push(node);
}
for (indx in path) {
path[indx].expand(true)
}
}
usage:
[your selector].dynatree("getRoot").find('needle');
Thanks to #mar10 i made a small, simple function to search a node with title:
// If searchFrom is null, root is used
function seachFolderNodeWithName(name, searchFrom) {
if (name == null) {
return undefined;
}
if (searchFrom == null) {
searchFrom = jQuery('#tree').dynatree("getRoot");
}
var match = undefined;
searchFrom.visit(function (node) {
if (node.data.title === name) {
match = node;
return false; // Break if found
}
});
return match;
};

Resources