Currently, based on JavaScript, I have embedded one tableau dashboard in a website, code is shown below. Now, I want to embed 2 dashboard in a same website (this second dashboard is from another tableau publish web link like the one I am using), how could I do it? Meanwhile, I need to create something like 'switch' button to allow me switch to different dashboard contents on click. Can anyone please help me with this?
Current code:
<!DOCTYPE html>
<html>
<head>
<title>Basic Embed</title>
<script type="text/javascript"
src="https://public.tableau.com/javascripts/api/tableau-2.min.js"></script>
<script type="text/javascript">
function initViz() {
var containerDiv = document.getElementById("vizContainer"),
url = "https://us-east-1.online.tableau.com/t/zuar/views/Regional/GlobalTemperatures",
options = {
hideTabs: true,
onFirstInteractive: function () {
console.log("Run this code when the viz has finished loading.");
}
};
var viz = new tableau.Viz(containerDiv, url, options);
// Create a viz object and embed it in the container div.
}
</script>
</head>
<body onload="initViz();">
<div id="vizContainer" style="width:800px; height:700px;"></div>
</body>
</html>
You could use a simple js-toggle func and toggle between the dashboards or whatever content you want to have. Just replace the text-content of the respective divs with the viz-containers of your dashboards..
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript"
src="https://public.tableau.com/javascripts/api/tableau-2.min.js">
</script>
<script>
function toggle() {
var x1 = document.getElementById("dashboard1");
var x2 = document.getElementById("dashboard2");
var bl = document.getElementById("button1");
if (x1.style.display === "none") {
x1.style.display = "block";
x2.style.display = "none";
bl.firstChild.data = "To Data B";
} else {
x1.style.display = "none";
x2.style.display = "block";
bl.firstChild.data = "To Data A";
}
}
function initialize() {
var containerDiv1 = document.getElementById("dashboard1"),
url1 = "https://public.tableau.com/views/liveintegration1/Dashboard1",
options1 = {
hideTabs: true,
onFirstInteractive: function () {
console.log("Run this code when the viz has finished loading.");
}
};
var viz1 = new tableau.Viz(containerDiv1, url1, options1);
// Create a viz object and embed it in the container div.
var containerDiv2 = document.getElementById("dashboard2"),
url2 ="https://public.tableau.com/views/LearnEmbeddedAnalytics/SalesOverviewDashboard",
options2 = {
hideTabs: true,
onFirstInteractive: function () {
console.log("Run this code when the viz has finished loading.");
}
};
var viz2 = new tableau.Viz(containerDiv2, url2, options2);
}
</script>
<style>
#dashboard1 {
border: 1px solid green;
width:800px;
height:700px;
width: 100%;
margin-top: 20px;
}
#dashboard2 {
border: 1px solid blue;
width:800px;
height:700px;
width: 100%;
margin-top: 20px;
}
</style>
</head>
<body onload="initialize()">
<button id="button1" onclick="toggle()">To Data B</button>
<div id="dashboard1" style="width:800px; height:700px;"></div>
<div id="dashboard2" style="width:800px; height:700px;"></div>
</body>
</html>
When inspecting the page you can now see the iframe being imported to the empty div:
Related
I've got the following problem: I want to access the css properties of styles.css inside Electron. The problem is that I can't use document.getElementsByClassName() because there is no document in Node. The desired behaviour is to change the color of one div once the q key is pressed.
This is my code:
index.js
const url = require('url');
const path = require('path');
const {app, BrowserWindow, globalShortcut} = require('electron');
let mainWindow;
app.on('ready', function(){
// Create new window
mainWindow = new BrowserWindow({backgroundColor: '#000000', fullscreen : true, frame : false});
// Load html in window
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes:true
}))
globalShortcut.register('Esc', () => {
app.quit();
});
globalShortcut.register('q', () => {
leftLight();
});
});
//This doesn't work
function leftLight() {
var element = ;
element.style["background-color"] = "yellow";
}
index.html
<!DOCTYPE html>
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<link rel="stylesheet" href="styles.css">
<title>Document</title>
</head>
<body>
<div class = rect_green> <h2 class=blocktext >LEFT FENCER</h2></div>
<div class = rect_red><h2 class=blocktext> RIGHT FENCER</h2> </div>
<div class = crono> <h2 class=blocktext>3:00</h2></div>
</body>
</html>
styles.css
.rect_green {
display: flex;
align-items: center;
height: 400px;
width:60%;
background-color: green;
position:relative;
top:100px;
text-align: center;
}
.rect_red {
display: flex;
align-items: center;
height:400px;
width:60%;
background-color: red;
position:relative;
top:120px;
float:right;
}
.crono {
display: flex;
align-items: center;
height:300px;
width:40%;
background-color: beige;
position:fixed;
left: 50%;
bottom : 50px;
transform: translate(-50%, 0px);
margin: 0 auto;
}
.blocktext {
margin-left: auto;
margin-right: auto;
font-family: "Palatino", Times, serif;
font-size: 180px;
}
Edit
After the modifications suggested by Gr8Miller (still no communication):
index.html
<!DOCTYPE html>
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<link rel="stylesheet" href="styles.css">
<title>Document</title>
</head>
<body>
<div class = rect_green> <h2 class=blocktext >LEFT FENCER</h2></div>
<div class = rect_red><h2 class=blocktext> RIGHT FENCER</h2> </div>
<div class = crono> <h2 class=blocktext>3:00</h2></div>
</body>
<script type="text/javascript">
var ipc = require('electron').ipcRenderer;
ipc.on('key-pressed-q', (e) => {
//var element = document.getElementsByClassName("rect_green");
//element.style["background-color"] = "yellow";
console.log("q pressed in html file");
});
</script>
</html>
And index.js
const url = require('url');
const path = require('path');
const {app, BrowserWindow, globalShortcut, ipcMain, webContents} = require('electron');
let mainWindow;
app.on('ready', function(){
// Create new window
mainWindow = new BrowserWindow({
backgroundColor: '#000000',
fullscreen : true,
frame : false,
icon : __dirname + "/res/icon.jpg",
webPreferences: {
nodeIntegration : true
}
});
// Load html in window
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes:true
}))
globalShortcut.register('Esc', () => {
app.quit();
});
globalShortcut.register('q', () => {
leftLight();
});
});
function leftLight() {
mainWindow && mainWindow.webContents.send('key-pressed-q');
console.log("Sending q pressed to html...");
}
Possible duplicate of this.
Try to create another js file containing your code and load it as a script from your html document.
Add this to your index.html:
<script type="text/javascript" charset="utf8" src="./pageScript.js"></script>
And create a separate pageScript.js file with the code you want:
window.onload = function () {
// your code here
function leftLight() {
var element = ;
element.style["background-color"] = "yellow";
}
// Also don't forget to call the function
leftLight();
}
View related tasks should be handled in render process but not main process.
in Electron, the entry js(index.js in your case) runs in main process (it acts manager of all browser windows it creates) and the browser window itself runs in render process. html elements and imported/embedded js "live"/"run" in browser windows(in render process), so document can only be directly accessed in render process.
in your case. the style change task should be done in render process:
send a message(e.g. key-pressed-q) to render process from the main process on key q is pressed:
change the style in render process on receiving message (key-pressed-q):
index.js
mainWindow = new BrowserWindow({
backgroundColor: '#000000',
fullscreen : true,
frame : false,
webPreferences: {
nodeIntegration: true
}});
...
function leftLight() {
mainWindow && mainWindow.webContents.send('key-pressed-q');
}
index.html
...
<script type="text/javascript">
var ipc = require('electron').ipcRenderer;
ipc.on('key-pressed-q', (e) => {
console.log(e);
var element = ;
element.style.backgroundColor = "yellow";
});
</script>
...
Added in 2019-11-18
There are other errors need to be fixed in your code which is not related to electron but just html basics:
//var element = document.getElementsByClassName("rect_green");
//element.style["background-color"] = "yellow";
getElementsByClassName returns an array of Element(Array<Element>) but not a single Element.
element.style doesn't have a field named background-color, it should be backgroundColor.
the console.log in the render process won't print logs in the main process's console, it outputs to its hosting browser window's own console. if you want to check the log, you have to open the browser window's Devtools first.
// in your `index.js`
// Open the DevTools.
mainWindow.webContents.openDevTools(); // `console.log` in `index.html` output to its hosting browser window's own console.
// in your `index.html`
var ipc = require('electron').ipcRenderer;
ipc.on('key-pressed-q', (e) => {
var element = document.querySelector(".rect_green");
element.style.backgroundColor = "yellow";
console.log("q pressed in html file"); // this won't output to the main process's console.
});
Change your index.html to this :
<!DOCTYPE html>
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<link rel="stylesheet" href="styles.css">
<title>Document</title>
</head>
<body>
<div class = rect_green> <h2 class=blocktext >LEFT FENCER</h2></div>
<div class = rect_red><h2 class=blocktext> RIGHT FENCER</h2> </div>
<div class = crono> <h2 class=blocktext>3:00</h2></div>
<script>
function leftLight() {
const element = document.getElementsByClassName("yourclassname")
element[0].style.color = "red"
}
window.onkeydown = function(e) {
if (e.key == "q") {
leftLight()
}
}
</script>
</body>
</html>
I want to use the DIV to display my report, so i see the icCube documentation icCube Web Reporting : Displaying a Report but when i try to apply it i'm confused about how can I putting the differents functions of the script to gather in the same html page , those are the functions:
The first Part
var ic3reporting = new ic3.Reporting({
noticesLevel: ic3.NoticeLevel.ERROR,
dsSettings: {
userName: "demo",
userPassword: "demo",
url: "http://localhost:8282/icCube/gvi"
}
});
ic3reporting.setupGVIConfiguration(function() {
ic3reporting.setupApplication({
mode: ic3.MainReportMode.REPORTING,
menu: ic3.MainReportMenuMode.OFF,
noticesLevel: ic3.NoticeLevel.ERROR,
container: $("#report-container")
});
});
The Second Part
var options = {
report: { name: 'My Report' },
mode: ic3.MainReportMode.EDITING_REPORTING,
menu: ic3.MainReportMenuMode.ON,
noticesLevel: ic3.NoticeLevel.INFO
};
ic3reporting.openReport(options, function() {
// your callback (I don't inderstand how can i putting this code)
});
I don't inderstand how can I put those parts to gather and
It's very important for me to build this script , That make the exportation of the report easier than before.
You can use these parts together in such way:
<!doctype html>
<head lang="en">
<meta charset="utf-8">
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%
}
</style>
</head>
<body>
<!-- 1. Define container for the report somewhere in html page -->
<div id="report-container"></div>
<!-- 2. Include reporting application scripts -->
<script src="http://localhost:8282/icCube/doc/ic3-report/app/reporting/js/loader/ic3bootstrap.js"></script>
<!-- 3. Initialization sequence -->
<script type="text/javascript">
var ic3root = "http://localhost:8282/icCube/doc/ic3-report/app/";
var ic3rootLocal = "http://localhost:8282/icCube/doc/ic3-report/app-local/";
// ic3reporting variable could be used globally, consider using array or different names here if
// you are going to show multiple report applications at the same time
var ic3reporting = null;
var options = {
root: ic3root,
rootLocal: ic3rootLocal,
// This function starts work just after initialization of reporting framework
callback: function () {
// 3.1 Create reporting instance with proper data source configuration
ic3reporting = new ic3.Reporting({
noticesLevel: ic3.NoticeLevel.ERROR,
dsSettings: {
userName: "demo",
userPassword: "demo",
url: "http://localhost:8282/icCube/gvi"
}
});
// 3.2 This function setups connection to the configured datasource and calls callback when connection is ready
ic3reporting.setupGVIConfiguration(function () {
// 3.3 Here we have ready connection, time to show empty reporting application
var initialApplicationOptions = {
mode: ic3.MainReportMode.REPORTING,
menu: ic3.MainReportMenuMode.OFF,
noticesLevel: ic3.NoticeLevel.ERROR,
container: $("#report-container")
};
ic3reporting.setupApplication(initialApplicationOptions);
// 3.4 just after setupApplication we have ready to work reporting environment, we can open reports, switch modes, etc
// here we have open report sequence
var options = {report: {name: 'My Report'}};
ic3reporting.openReport(options, function () {
alert("Report opened successfully")
});
});
}
};
ic3ready(options);
</script>
</body>
</html>
This is the correcte code
<html>
<head lang="en">
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<!-- ic3 bootstrap javascript -->
<script src="http://localhost:8282/icCube/doc/ic3-report/app/reporting /js/loader/ic3bootstrap.js"></script>
<script type="text/javascript">
/**
* Location of the icCube reporting files; not necessarily co-located
* with this HTML page. For example, assuming this file is located within
* the "Docs" repository of a local icCube install, this path would be :
*
* /icCube/doc/ic3-report/app/reporting/
*/
var ic3root = "http://localhost:8282/icCube/doc/ic3-report/app/";
var ic3rootLocal = "http://localhost:8282/icCube/doc/ic3-report/app-local/";
var options = {
root: ic3root,
rootLocal: ic3rootLocal,
callback: function () {
var ic3reporting = new ic3.Reporting(
{
noticesLevel:ic3.NoticeLevel.ERROR,
dsSettings:{
userName:"demo",
userPassword:"demo",
url: "http://localhost:8282/icCube/gvi"
}
});
ic3reporting.setupGVIConfiguration(function () {
ic3reporting.setupApplication(
{
mode:ic3.MainReportMode.REPORTING,
menu:ic3.MainReportMenuMode.OFF,
noticesLevel:ic3.NoticeLevel.ERROR,
container:$(".ic3-report-content-container")
});
var options = {
report:{
name:'rapportest'
},
mode:ic3.MainReportMode.EDITING_REPORTING,
menu:ic3.MainReportMenuMode.OFF,
noticesLevel:ic3.NoticeLevel.INFO
};
ic3reporting.openReport(options, function () {
alert("Report opened successfully")
});
});
}
};
ic3ready(options);
</script>
<div class="ic3-report-content-container" style="border:solid 1px red;"></div>
I am writing code for image slide Show using Java Script and HTML 5. I am using SetInterval() method to call ImageSlider Function repeatedly. Problem is Imageslider function is called only once.
Here is my code
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Online Booking</title>
</head>
<style>
iframe
{
display:block;
float:middle;
margin: 0 auto;
text-align: center
}
</style>
<body onload="init()">
<script>
function init()
{
setInterval(imageSlider(),5000);
}
function staticVar()
{
if (staticVar.counter == undefined)
{
staticVar.counter = 1
}
else
{
staticVar.counter++
}
return staticVar.counter;
}
function imageSlider()
{
alert("sl");
var j= staticVar();
var imgArray = new Array();
imgArray[0] = new Image();
imgArray[0].src = '91.jpg';
imgArray[1] = new Image();
imgArray[1].src = 'myBro.jpg';
imgArray[2] = new Image();
imgArray[2].src = 'me.jpg';
document.getElementById("imageSlide").src = imgArray[j].src;
}
</script>
<iframe height="580" width="25%" src="91.jpg" id="imageSlide"> </iframe>
</body >
</html>
You need to use
setInterval(imageSlider,5000);
instead of
setInterval(imageSlider(),5000);
Documentation on setInterval().
I would like to add an event listener to my image object so that when clicked it destroys itself but it doesn't seem to do anything.
var tshirtS = new Image();
tshirtS.onload = function () {
var tshirtSk = new Kinetic.Image({
image: tshirtS,
width: 50,
height: 58,
listening: true
});
tshirtS.on('click', function() {
tshirtS.destroy();
});
// add the image to the layer
layer2.add(tshirtSk);
typeOptions.add(tshirtSk);
stage.add(layer2);
typeOptions.draw();
return tshirtSk;
};
tshirtS.src = 'tshirt-small.png';
A couple of glitches in your code:
tshirtSk is the object you should assign the click event to
after you destroy the tshirtSk, you must redraw the layer to un-display tshirtSk
Fixed code:
// not tshirtS.on('click',function(){
tshirtSk.on('click', function() {
tshirtSk.destroy();
layer2.draw();
});
Good luck with your project!
A Demo: http://jsfiddle.net/m1erickson/DcjnF/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.2.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer2 = new Kinetic.Layer();
stage.add(layer2);
var tshirtS = new Image();
tshirtS.onload = function () {
var tshirtSk = new Kinetic.Image({
image: tshirtS,
width: 50,
height: 58,
listening: true
});
//
tshirtSk.on('click', function() {
tshirtSk.destroy();
layer2.draw();
});
// add the image to the layer
layer2.add(tshirtSk);
layer2.draw();
return tshirtSk;
};
tshirtS.src = 'https://dl.dropboxusercontent.com/u/139992952/multple/T-Shirt_blue.png';
}); // end $(function(){});
</script>
</head>
<body>
<h4>Click to destroy the T-shirt.</h4>
<div id="container"></div>
</body>
</html>
[ Addition: add image on stage click ]
You can listen for clicks on tshirtSk and add a new image like this:
tshirtSk.on('click', function (event) {
layer2.add(new Kinetic.Image({image:yourOtherImage}));
layer2.draw();
});
I'm having a problem getting my code to work when it's incororated into a live site. The fiddle works just fine, but when I include the identical code in a webpage, I can't get the function to load/work at all.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Drag and Drop Assignment</title>
<!doctype html>
<link rel="stylesheet" href="styles/style1.css"/>
<style>
.drop{
float: left;
width: 350px;
height: 400px;
border: 3px solid blue;
background-image: url("http://debsiepalmer.com/images/tardis 2.jpg");
background-repeat: no-repeat;
background-size: cover;
}
#right{float: left;
width: 350px;
height: 400px;
border: 3px solid red;
}
</style>
<script src="draganddrop.js" ></script>
<script src="http://code.jquery.com/jquery-2.0.2.js" ></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js" ></script>
<script type="text/javascript">
$ (init);
function image(id, image1) {
this.id = id;
this.image1 = image1;
}
$('#deal').click(function () {dealAll(
dealCard(randomCard()));
});
$(function() {
$( "#draggable" ).draggable({ containment: "#left"});
});
function init() {
$('.drop').droppable( {
drop: handleDropEvent
} );
$("img").draggable();
}
// global variables
var cardsInDeck = new Array();
var numberOfCardsInDeck = 15;
cardsInDeck[0] = "Ace";
cardsInDeck[1] = "Grace";
cardsInDeck[2] = "Susan";
cardsInDeck[3] = "Ian";
cardsInDeck[4] = "Barbara";
cardsInDeck[5] = "Brigadier";
cardsInDeck[6] = "Romana I";
cardsInDeck[7] = "K9";
cardsInDeck[8] = "Tegan";
cardsInDeck[9] = "Jamie";
cardsInDeck[10] = "Sarah Jane";
cardsInDeck[11] = "Jo";
cardsInDeck[12] = "Romana II";
cardsInDeck[13] = "Yates";
cardsInDeck[14] = "Leela";
var cardsDealt = new Array();
function dealAll(){
var z=0;
for (z=0;z<5;z++) {
cardsDealt[z] = new Image(z,dealCard(randomCard()));
}
}
function dealCard(i) {
if (numberOfCardsInDeck == 0) return false;
var $img = new Image();
$img.src = "images/Companions/" + cardsInDeck[i] + ".jpg";
// Here I set the ID of the object
$img.id=cardsInDeck[i];
$img.class='drag';
document.body.appendChild($img);
$('#'+$img.id).draggable();
removeCard(i);
return $img;
}
// deal randomly - works
function randomCard() {
return Math.floor(Math.random() * numberOfCardsInDeck);
}
function removeCard(c)
{
for (j=c; j <= numberOfCardsInDeck - 2; j++)
{
cardsInDeck[j] = cardsInDeck[j+1];
}
numberOfCardsInDeck--;
numberOfCardsInDeck--;
numberOfCardsInDeck--;
}
function handleDropEvent( event, ui ) {
alert("Fantastic! You chose " + ui.draggable.attr("id") + " to be your companion.");
// Here I want the id of the dropped object
}
</script>
</head>
<body>
<div id="container" div style="width:750px; margin:0 auto;">
<div id="page_content" style="left: 0px; top: 0px; width: 750px" class="auto-style8">
<!--Begin Assignment 10 --->
<div id="left" class="drop">
<img id="tardis" ></img>
</div>
<input type="button" value="Get Companions" id="deal" />
<div id="content" style="left: 0px; top: 0px; width: 750px">
</div>
</div>
</div>
</body>
</html>
It's supposed to generate 5 images, one of which can be selected to be dropped onto the target and generate an alert with the id of the image being dropped. Like I said, it works just fine in the fiddle - and the code is identical on the web page, so I don't understand what I'm doing wrong.
fiddle: http://jsfiddle.net/reaglin/FUvT8/6/
I ordered some code...and for me it worked
// global variables
var cardsInDeck = [],
numberOfCardsInDeck = 5;
cardsInDeck[0] = "Ace";
cardsInDeck[1] = "Grace";
cardsInDeck[2] = "Susan";
cardsInDeck[3] = "Ian";
cardsInDeck[4] = "Barbara";
cardsInDeck[5] = "Brigadier";
cardsInDeck[6] = "Romana I";
cardsInDeck[7] = "K9";
cardsInDeck[8] = "Tegan";
cardsInDeck[9] = "Jamie";
cardsInDeck[10] = "Sarah Jane";
cardsInDeck[11] = "Jo";
cardsInDeck[12] = "Romana II";
cardsInDeck[13] = "Yates";
cardsInDeck[14] = "Leela";
//load "init" when document it's ready
$(document).on('ready',init);
function init() {
$( "#draggable" ).draggable({ containment: "#left"});
$('.drop').droppable( {drop: handleDropEvent});
}
$('#deal').click(function () {
dealAll();
});
$('#reset-pictures').click(function(){
$('img.drag').remove();
numberOfCardsInDeck = 5;
});
// deal 5 cards at once - works
function dealAll(){
// 5 cards max, no repeat cards
while(numberOfCardsInDeck){
var rand = randomCard();
dealCard(rand);
}
}
//deal cards - works
function dealCard(i) {
//create id, remove space id
var id_picture = (cardsInDeck[i] +'-'+i).replace(/\s/g, '');
//validate not exist image
if (!!$('img#'+id_picture).length) {
return;
}
var $img = $('<img/>', { src : "http://debsiepalmer.com/images/companions/" + cardsInDeck[i] + ".jpg", id : id_picture, class : 'drag', 'data-info': cardsInDeck[i]
})
$('body').append($img);
$('img.drag').draggable();
numberOfCardsInDeck--;
}
// deal randomly - works
function randomCard() {
return Math.floor(Math.random() * cardsInDeck.length);
}
// this is what to do when card drops in tardis
function handleDropEvent( event, ui ) {
alert(ui.draggable.attr("data-info"));
}
DEMO
JSFinddle
Are you linking to JQuery correctly in the live version? Sometimes when moving from a development area to a live system the references mess up, you can find out if a reference is working or not by viewing the source code and entering in the link into the URL.
This is how you fix it: Take all the javascript (from $ (init) to the alert()) and place it at the bottom of the loaded page, inside the body, after all the elements. This ensures that the javascript knows what named elements you are talking about.
I would like to emphasise that this is not a tip for writing good javascript. The problem arises because it's bad javascript to begin with. Well written pages do not rely on the position of the code within the page, rather the opposite in fact.
Postscript: I literally did the following: I came here after googling "drag and drop"; I didn't fully read the actual question; I went to the jfiddle; I copied all the code for my own purposes; I couldn't get it to work; I fixed it (just trial and error really); I fixed the bug which is still present even on the jfiddle page; and then I came back here to find out what the original query had been!
The other bug is the fact that you can't drag the images of "Romana I", "Romana II" and "Sarah Jane". As the code makes the array values the id of the image elements, maybe others can instantly spot what causes that problem.