HTMLWidget: Shiny app run well in Rstudio but Not on Shiny-Server - javascript

Recently I have written a html widget to use a javascript file for venn diagram plotting. In RStudio the app works fine so I didn’t realize so far that there is an issue using the app on the shiny server.
If I run the app in with Shiny in RStudio no error is throw and the Web browser shows all other elements of my Shiny page except the new widget. Considering the developer console of the browser I see the following error which is kind of cryptically for me.
Uncaught TypeError: Cannot read property 'filter' of undefined
at exports.OutputBinding.shinyBinding.find (htmlwidgets.js:475)
at a (shiny.min.js:3)
at f (shiny.min.js:3)
at initShiny (shiny.min.js:3)
I also run it outside of RStudio just to get sure but same error.
I have tested this with 2 independent packages so its seems to be a systematical error on my side.
By inspecting the running app in the browser I saw that the following div is created. However, I couldn’t find the submitted data.
<div id="vennDia" style="width:100%; height:400px; " class="vennConductor html-widget html-widget-output"></div>
vennConductor.js:
HTMLWidgets.widget({
name: 'vennConductor',
type: 'output',
initialize: function(el, width, height) {
},
renderValue: function(el, x, instance) {
// console.log(x)
$(el).jvenn(x)},
resize: function(el, width, height, instance) {
$(el).attr("width", width).attr("height", height)
}
});
In my opinion “relevant” HTMLWidget R code:
htmlwidgets::createWidget(
name = 'vennConductor',
json_payload,
width = width,
height = height,
package = 'vennConductor',
elementId = elementId,
sizingPolicy = htmlwidgets::sizingPolicy(
browser.fill = TRUE,
viewer.fill = TRUE
)
)
#' #name vennConductor-shiny
#' #export
vennConductorOutput <- function(outputId, width = '100%', height = '400px'){
htmlwidgets::shinyWidgetOutput(outputId, 'vennConductor', width, height, package = 'vennConductor')
}
#' #rdname vennConductor-shiny
#' #export
renderVennConductor <- function(expr, env = parent.frame(), quoted = FALSE) {
if (!quoted) { expr <- substitute(expr) } # force quoted
htmlwidgets::shinyRenderWidget(expr, vennConductorOutput, env, quoted = TRUE)
}
and the widget call:
jVennConductor(elementId = 'vennDia', venn_lists = vlist_01, displayMode=T, displayStat=T)
Hope anyone can help me out. Thanks!!!
P.s.: R and a Packages are up-to-date and my OS is WINDOWS 10.

We have found the reason for the problem. Shiny imports jquery by lowercase, jVennConductor by uppercase and that is what causes the error. Simple change both to lowercase solved the problem.
Thanks to Joe Cheng
https://github.com/ramnathv/htmlwidgets/issues/253

Related

Instead of creating new chart in ChartJS, the new updated chart keeps the old data and adds the new

I have been trying to solve this problem with ChartJS for a few days now, and I am completely stumped
My program shows the user a set of input elements they use to select data needing to be charted, plus a button that has an event to chart their data. The first chart works great. If they make a change to the data and click the button a second, third, or more time, all the data from the previous charts is plotted, PLUS their most recent selection.
It is behaving exactly like you might expect if the chart.destroy() object is not working, or perhaps would work if I created the chart object using a CONST (and could therefore add new data but not delete the beginning data).
I have tried all combinations of the browsers, chartjs and jquery libraries below:
Three different browsers:
• Chrome: Version 107.0.5304.121 (Official Build) (64-bit)
• Microsoft Edge: Version 107.0.1418.56 (Official build) (64-bit)
• Firefox: 107.0 64-bit
I have tried at least three different versions of Chart.js, including
• Versions 3.9.1
• 3.6.2
• 3.7.0
Jquery.js
• v3.6.1
• v1.11.1
Other things I have tried:
"use strict" (no luck)
In addition to destroying the chart object, removed the div containing the canvas, and appending it again.
using setTimeout() function before updating the chart after destroying it (because I thought maybe giving the destroy method more time might help)
type here
Software:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/chart.js"></script>
<script type="text/javascript" src="js/dropdownLists.js"></script>
<script type="text/javascript" src="js/chartDataFunctions.js"></script>
<script type="text/javascript" src="js/chartJSFunctions.js"></script>
<body>
<div class = metadatasetup4" id = "buttons">
<button class="download" id="getchart" value="Get Chart">Chart</button>
<button class="download" id="downloadchart" value="Download">Download</button>
</div>
<div id = "bigchartdiv" class="bigchart">
<canvas id="myChart"></canvas>
</div>
</body>
<script>
$(window).on('load',function(){
//NOTE 1: In of my attempts to troubleshoot I tried strict mode (it didn't work)
//"use strict";
let data = {
labels: lbl,
datasets: [
]
};
let config = {
type: 'line',
data: data,
options: {
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
min:0,
pointStyle:'circle',
},
y1: {
type: 'linear',
display: true,
position: 'right',
suggestedMax: 25,
min: 0,
pointStyle: 'cross',
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
}
}
};
// NOTE 2: The next line below, beginning with "var bigChartHTML =" was one of my later attempts to
// solve the problem. It didn't work, but my thought process was that if I removed
// the div containing the canvas, AND destroyed the chart object, that appending a "fresh"
// chart div to the body might be a work-around. This did not work.
var bigChartHTML = '<div id = "bigchartdiv" class="bigchart"><canvas id="myChart"></canvas></div>'
let ctx = document.getElementById('myChart').getContext('2d');
let bigChart = null;
// The getChartData() function below uses Ajax to populate various dropdown lists
// which enable the user to select the data is to be charted.
// There are no chartjs-related operations in getChartData()
getChartData();
$('#buttons').on('click','#getchart',function(){
if (bigChart!=null) {
//removeData(bigChart);
bigChart.destroy();
//bigChart = 1;
}
$("#bigchartdiv").empty(); //for this and next 2 lines, see NOTE 2 above
$("#bigchartdiv").remove();
$(bigChartHTML).insertAfter("#chartcontrols");
bigChart = new Chart(document.getElementById('myChart'),config);
//NOTE 3: I thought maybe bigChart.destroy() took time, so I tried
// using the setTimeout function to delay updating the chart
// (didn't work, but I left it in the code, anyway.)
setTimeout(function() {updateChart(bigChart)}, 2000);
//updateChart(bigChart);
});
// NOTE: The updateChart() function is actually included in "js/chartDataFunctions.js"
function updateChart(chart) {
/*
This section of the program reads the HTML elements then uses them
to make an Ajax request to sql server, and these become the
parameters for the newDataSet() function below.
*/
newDataset(chart,firstElement,newdataset,backgroundcolor,color);
}
// NOTE: The newDataSet() function is actually included in "js/chartJSFunctions.js"
// I show it here for brevity.
// It decides which axis (y or y1) to use to plot the datasets
// the dataset is pushed into the data, and chart.update() puts it in the chart object
function newDataset(chart,label,data,bgcolor='white',color='rgb(255,255,255)') {
var maxValue = Math.max(...data);
if (Number.isNaN(maxValue)) {
return;
}
if (maxValue == 0) {
return;
}
var axisID = 'y';
var ptStyle = 'circle';
//var pStyle = 'circle';
if (maxValue < 50) {
axisID = 'y1';
bgcolor = 'white';
//ptStyle = 'Star'
}
chart.data.datasets.push({
label:label,
yAxisID:axisID,
data:data,
borderColor:color,
backgroundColor:bgcolor,
//pointStyle:ptStyle
});
chart.update();
}
});
</script>
I found a work-around that solves my problem, but I still think this is a bug in ChartJS. Before calling bigChart.destroy(), I now do two things: First, reset the data object back to it's original value, and second, reset the config object back to it's original value, THEN call bigChart.destroy().
I think the destroy() method should handle that for me, but in my case, for whatever reason, it doesn't.
So, what I have is a work-around, not really a solution, but I'll take it.

kiosk app full screen

I have built a kiosk app for Chrome with app builder, but even if the key of doing a kiosk app is that it will be displayed at full screen, I don´t manage to get rid of the top bar (I have removed the homepage button etc. but can´t display it at total full screen). I`d like to know if there´s any commando for this in html or javascript and in which file it should be added.
In the backgroung.js file I´ve added the line "state: 'fullscreen' but it does not work (I've also added the permission for fullscreen in the manifest file):
var runApp = function() {
if (chrome.power) {
chrome.power.requestKeepAwake('display');
}
console.log(config);
chrome.app.window.create(
config ?
'exported_app_view.html' :
'designer_view.html',
{
id: 'KioskDesignerWindow',
width: 1100,
height: 720,
minWidth: 800,
minHeight: 600,
state: 'fullscreen'
},
function(win) {
if (!this.X) { return; }
var window = win.contentWindow;
window.onload = function() {
this.$addWindow(window);
var Y = this.X.subWindow(window, 'Kiosk Designer Window');
this.DOM.init(Y);
}.bind(this);
win.onClosed.addListener(function() {
this.$removeWindow(window);
}.bind(this));
}.bind(this));
}.bind(this);
Yes, you can do it with JavaScript. In background.js, your 3rd parameter to chrome.app.window.create is that callback function that has the win argument - add this line:
win.fullscreen();
https://developer.chrome.com/apps/app_window#type-AppWindow
If you hit escape while your app is running you may get the title bar back, but next time it runs it will go fullscreen again.

html5/javascript game running slow in ie8

We have made a game in html/javascript. There's unfortunately a lot of secrecy around the project, so I can't disclose much code.
However the essence is that it runs extremely well on all browsers, except ie. through using the <meta http-equiv="X-UA-Compatible" content="IE=9"> tag; now the only problem is ie8, which the game NEEDS to be compatible with. I know it has little html5 integration, but the game actually works, except it's horribly slow.
Keep in mind, ie9 and ie10 were very slow before using the tag as well. The game is in n sense advanced or anything. So I was wondering if anyone knew what could cause issues like these?
I'll try to put some obfuscated code here, keep in mind though that it's not the entire code, just the main loop:
// Global constants:
var PLAYGROUND_WIDTH = 1000;
var PLAYGROUND_HEIGHT = 1000;
var REFRESH_RATE = 30;
//Constants for the gameplay
var smallStarSpeed = 1; //pixels per frame
var mediumStarSpeed = 3; //pixels per frame
var bigStarSpeed = 5; //pixels per frame
var percent = 1;
// --------------------------------------------------------------------
// -- the main declaration: --
// --------------------------------------------------------------------
$(function(){
//Calculate playground width and height:
PLAYGROUND_WIDTH = $(window).width() - 20;
PLAYGROUND_HEIGHT = $(window).height() - 20;
//Calculate Layour for responsive Design.
//Calculate Area:
// Animations declaration:
// The background:
var DM = new DeckManager;
var IM = new ImageManager;
IM.Create("Image1");
//DEBUG: Loading images for demo, this should be done using the image manager in the actual game.
var background1 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background1.png"});
var background2 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background2.png"});
var background3 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background3.png"});
var background4 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background4.png"});
var background5 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background5.png"});
var background6 = new $.gameQuery.Animation({
imageURL: "http://gamequeryjs.com/demos/3/background6.png"});
var Face = new Array();
IM.Load("image2");
IM.Load("image3");
IM.Load("image4");
IM.Load("image5");
var resizeTimer;
//Event to handle resizing
//This event should fire under any circimstance, except when safari is NOT maximized, and windows resolution is changed (WTF?)
$(window).resize(function ()
{
clearTimeout(resizeTimer);
resizeTimer = setTimeout(Resized, 100);
});
//Actual Resizing Event
function Resized()
{
//Your function goes here
//Calculate playground width and height:
PLAYGROUND_WIDTH = $(window).width() - 20;
PLAYGROUND_HEIGHT = $(window).height() - 20;
//Calculate Layout for responsive Design.
};
// Initialize the game:
$("#playground").playground({
height: PLAYGROUND_HEIGHT,
width: PLAYGROUND_WIDTH,
keyTracker: true,
mouseTracker: true});
// Initialize the background
$.playground()
.addGroup("background", {width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT})
.addSprite("background1", {animation: background1,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT})
.addSprite("background2", {animation: background2,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT,
posx: PLAYGROUND_WIDTH})
.addSprite("background3", {animation: background3,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT})
.addSprite("background4", {animation: background4,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT,
posx: PLAYGROUND_WIDTH})
.addSprite("background5", {animation: background5,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT})
.addSprite("background6", {animation: background6,
width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT,
posx: PLAYGROUND_WIDTH})
$("#background").addSound(bgmusic);
//Setup obects so they can be reached randomly
var Vals = new Array();
var Vals2 = new Array();
var Turned = 0;
var TurnedMax = 2;
//This will ensure that two cards of each are added to the deck
//This function will be handled by the imagemanager at later stages.
for (var i = 0; i < NumberOfCards; ++i)
{
Vals[i] = Math.floor(i/2);
}
Vals2[0]=3;
DM.Create(Vals, Vals2, NumberOfCards, 1);
//Generate the actual object
$.playground()
.addGroup("object", {width: PLAYGROUND_WIDTH,
height: PLAYGROUND_HEIGHT})
for (var i = 0; i < NumberOfCards+1; ++i)
{
//Generate unique ID for the card
var name = "object"+i;
val = DM.Pushobject();
//Add the actual card to the playground, we spawn them in a responsive awy based on the resolution of the game.
$("#object").addSprite(name, {animation: IM.GetBack(), width: 208, height: 303, posx: (i%(Math.ceil(noc*Ratio))) *SpaceX + SpaceX - 104 + LastYOff * ( i>= (NumberOfCards + NumberOfCardsBonus) - ((NumberOfCards + NumberOfCardsBonus)%(Math.ceil(noc*Ratio))) ) , posy: Math.floor( i / (Math.ceil(noc*Ratio)) ) * SpaceY + SpaceY - 152 });//
//Add a class to the object, this, does nothing except make us able to search for objects with the same class later in the code.
$("#"+name).addClass("object");
//Create the actual class for the object, this will add logic to the object.
$("#"+name)[0].Cards = new Cards($("#"+name));
$("#"+name)[0].Cards.Create(val, IM.GetImage(val), IM.GetImage(3), IM.GetBack(), DM.LastBonus(), Scale);
//Add a mousedown event for the card, this mousedown will be run in the main
//environment rather than the class environment to make sure that we have access
//to all the data we need access to.
$("#"+name).mousedown(function(e)
{
var Ready = 0;
$(".object").each(function()
{
if (this.object.visible && (this.object.Turning==true || this.object.FlippedV==true))
{
Ready++;
}
});
//Find all the objects with the tag/class card.
$(".object").each(function()
{
//Check if the mouse clicked the object, if it's still part of the game, and if it has not been flipped.
if (e.clickedobject
&& Ready<TurnedMax)
{
//Run the clicked event for the card, this will start events etc.
this.object.Clicked();
//Increase the turned counter, if we have turned the correct amount of objectto be compared
//then compare them.
if (this.Cards.Bonus == false)
{
Turned++;
if (Turned==TurnedMax)
{
//We have turned the amount of object needed
//Find out which value the first object has, and use this as a base to compare if cards match.
//Also instantiate a counter for the amount of cards actually matching.
//It's done this way if you want a variable number of object needed for a match.
var Correct = this.object.value;
var CorrectAmount = 0;
$(".object").each(function()
{
//For each card, if they are flipped, are not going into hiding/deletion, and has the
//Correct value, increase the counter for the number of objects matching.
if (this.object.Flipped == true && this.object.Hiding==0 && this.object.value == Correct)
CorrectAmount++;
});
//If we have a correct match
if (CorrectAmount==TurnedMax)
{
$(".object").each(function()
{
//Foreach object that is flipped and not in hiding, delete them (aka. yay, you got a match).
if (this.object.Flipped==true && this.object.Hiding==0)
this.object.SetVisible(false);
});
}
$(".object").each(function()
{
//Foreach objectthat was not in hiding and was not part of the match, unflip them again.
if (this.object.Flipped==true && this.object.Hiding==0)
this.object.Hide();
});
Turned=0;
}
}
}
});
});
}
// this sets the id of the loading bar (NOT USED YET):
$.loadCallback(function(percent){
$("#loadingBar").width(400*percent);
});
//initialize the start button
$("#startbutton").click(function(){
$.playground().startGame(function(){
$("#welcomeScreen").remove();
});
})
//This is for the background animation (DEBUG)
$("#playground").registerCallback(function(){
$("#background1").x(($("#background1").x() + smallStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
$("#background2").x(($("#background2").x() + smallStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
$("#background3").x(($("#background3").x() + mediumStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
$("#background4").x(($("#background4").x() + mediumStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
$("#background5").x(($("#background5").x() + bigStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
$("#background6").x(($("#background6").x() + bigStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
//Basic Game Engine!!
$(".object").each(function()
{
//For each card, perform their step event.
this.object.Step();
});
}, REFRESH_RATE);
});
You say you're using <meta http-equiv="X-UA-Compatible" content="IE=9">.
That's is unlikely to be helpful in any way at all.
It will have no effect at all in IE9 or IE8.
It will be having an effect in IE10 and IE11, but that effect will be to pull the browser down into backward-compatibility mode, which basically means that you're telling IE10 and higher to switch off some of their newer features and pretend to be IE9.
There's really no point in that at all; in fact, it's probably doing more harm than good, so I recommend removing that line of code entirely.
If you must have an X-UA-Compatible flag, the only sensible value for it is IE=edge. This will force all IE versions to use the best mode they have available. That's the default anyway in most cases, but it might help in the few cases where the default is something else.
But the real problem you're complaining about here is performance, and I can tell you categorically that this is entirely unrelated to the X-UA-Compatible flag -- as I say, the way you have it set won't have any effect on IE8 at all anyway, so it's not that which is slowing things down.
Ultimately, your problem with IE8 may boil down to the simple fact that it is just a much much slower browser than later versions. It is possible that you may simply not be able to get IE8 to perform well enough to achieve what you want.
IE9 and IE10 are much better, so you should be able to get reasonable performance from them with a bit of tweaking, so your best hope would probably be to do some performance tuning.
And the best bet for performance testing is to upgrade to IE11, which has much better dev tools than IE10, including some really good tools for analysing your site's performance.
Performance tuning is big topic in itself (out of scope for this answer), but the ultimate goal is to work out what is causing your biggest bottlenecks, and fix those. In most cases there's generally just one or two major issues that hold everything up, and dealing with them is usually sufficient to make the difference.
So my advice is: Download IE11 and try out the new performance testing features in the new dev tools. Hopfully that'll be enough to get you started, but if you still can't find the problem, try asking a more specific question about whay a particular bit of your code is slow.
One other thing I would suggest is maybe to try reducing your use of libraries like jQuery.
jQuery is incredibly useful, but it does have a performance impact. Try switching to native Javascript where possible.
And where you can't, try reducing the number of times you make the same call. For example:
$("#background1").x(($("#background1").x() + smallStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
This calls $("#background1") twice. Do this instead:
var $bg1 = $("#background1");
$bg1.x(($bg1.x() + smallStarSpeed +PLAYGROUND_WIDTH) % (2 * PLAYGROUND_WIDTH) - PLAYGROUND_WIDTH);
Better yet, if you can do it with document.getElementByTagName rather than jQuery, you'll save yourself even more performance.
I also notice that you're repeating some calculations in that code. Obviously, if you can tidy that up to reduce the repeats, it will also help.
I hope that's given you some directions to think.
Put <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" >
in your html head tag and try. Switching the compatibility view on turns IE into IE8 rendering.
http://html5test.com/compare/browser/ie08/chrome28/ff22.html

Embedding Ventus in WT

Hello fellow programmers! My goal is to embed a Ventus window manager (http://www.rlamana.es/ventus/), repo here (https://github.com/rlamana/Ventus) in a WT page (http://www.webtoolkit.eu/wt) and get the "Simple Example" running. I have the ventus window embedded in the WT page, however I am having a styling problem with the window. My guess this is a conflict with CSS of Ventus and WT. Which brings me here, as CSS is not my strong point. I am using visual studio2010 for my development, and I have the bare minimum of a WT project running, basically the hello world app with all the widgets ripped out of it. I've included all the CSS and JS that the simple.html example uses, and have been trying to figure out how to make it work with WT. Any help would be much appreciated!
void HelloApplication::InitInterface()
{
//Include the CSS
wApp->useStyleSheet("Ventus/examples/simple/css/normalize.css");
wApp->useStyleSheet("Ventus/examples/simple/css/simple.css");
wApp->useStyleSheet("Ventus/build/ventus.css");
wApp->useStyleSheet("Ventus/examples/simple/css/browseralert.css");
//Include the JS
wApp->require("Ventus/vendor/modernizr.js");
wApp->require("Ventus/vendor/jquery.js");
wApp->require("Ventus/vendor/handlebars.js");
wApp->require("Ventus/build/ventus.js");
WContainerWidget* root = this->root();
WContainerWidget* ventus_widget = new WContainerWidget(root);
//Widget ref
std::string ventus_widget_ref = ventus_widget->jsRef(); // is a text string that will be the element when executed in JS
std::string command = ventus_widget_ref + ".wm = new Ventus.WindowManager();";
//Create the window manager
ventus_widget->doJavaScript(command);
command = ventus_widget_ref + ".wm.createWindow({title: 'Ventus', x: 10, y: 10, width: 500, height: 500}).open();";
//You may also create new windows by creating container widgets and fromQuery function
//WContainerWidget* app_window = new WContainerWidget(wApp->root());
//command = ventus_widget_ref + ".wm.createWindow.fromQuery(" + app_window->jsRef() + ", {title: 'Ventus', x: 10, y: 10, width: 500, height: 500}).open();";
//You can then add widgets to the ventus window like any other WT container
//app_window->addWidget(app.get());
//Create a window
ventus_widget->doJavaScript(command);
}
Finally figured it out. When using WT instead of using "require" for loading CSS files, use "useStyleSheet".

How to update the source of an Image

I'm using the Raphaël Javascript lib (awesome stuff for SVG rendering, by the way) and am currently trying to update the source of an image as the mouse goes over it.
The thing is I can't find anything about it (it's probably not even possible, considering I've read a huge part of the Raphaël's source without finding anything related to that).
Does someone knows a way to do this ?
Maybe it can be done without directly using the Raphaël's API, but as the generated DOM elements doesn't have IDs I don't know how to manually change their properties.
I'm actually doing CoffeeScript, but it's really easy to understand. CoffeeScript is Javascript after all.
This is what I'm doing right know, and I would like the MouseOver and MouseOut methods to change the source of the "bg" attribute.
class Avatar
constructor: (father, pic, posx, posy) ->
#bg = father.container.image "pics/avatar-bg.png", posx, posy, 112, 112
#avatar = father.container.image pic, posx + 10, posy + 10, 92, 92
mouseOver = => #MouseOver()
mouseOut = => #MouseOut()
#bg.mouseover mouseOver
#bg.mouseout mouseOut
MouseOver: ->
#bg.src = "pics/avatar-bg-hovered.png"
alert "Hover"
MouseOut: ->
#bg.src = "pics/avatar-bg.png"
alert "Unhovered"
class Slider
constructor: ->
#container = Raphael "raphael", 320, 200
#sliderTab = new Array()
AddAvatar: (pic) ->
#sliderTab.push new Avatar this, pic, 10, 10
window.onload = ->
avatar = new Slider()
avatar.AddAvatar "pics/daAvatar.png"
This actually works, except for the "#bg.src" part : I wrote it knowing that it wouldn't work, but well...
var paper = Raphael("placeholder", 800, 600);
var c = paper.image("apple.png", 100, 100, 600, 400);
c.node.href.baseVal = "cherry.png"
I hope, you get the idea.
This works for me (and across all browsers):
targetImg.attr({src: "http://newlocation/image.png"})
I was using rmflow's answer until I started testing in IE8 and below which returned undefined for image.node.href.baseVal. IE8 and below did see image.node.src though so I wrote functions getImgSrc, setImgSrc so I can target all browsers.
function getImgSrc(targetImg) {
if (targetImg.node.src) {
return targetImg.node.src;
} else {
return targetImg.node.href.baseVal;
}
}
function setImgSrc(targetImg, newSrc) {
if (targetImg.node.src) {
targetImg.node.src = newSrc;
} else {
targetImg.node.href.baseVal = newSrc;
}
}

Categories