d3.js donut chart - add drop shadow to the highlighted section - javascript

In my project, I am using d3.js donut chart to display some data. On click of each of the arc sections, it will be highlighted. The requirement is to add a drop shadow effect to the highlighted section when clicked, so it will highlighted much more. I am using stroke to create a shadow effect, but it is not looking like a shadow.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title> D3 Js Example </title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
</head>
<body>
<div id="my_dataviz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.7/d3.min.js" ></script>
<script>
var lastSelected = "";
var firstSelected = "";
var width = 450
height = 450
margin = 40
var radius = Math.min(width, height) / 2 - margin
var normalArc = d3.arc().outerRadius(radius - 30).innerRadius(radius - 70);
var biggerArc = d3.arc().outerRadius(radius - 80).innerRadius(radius - 10);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var data = {a: 9, b: 20, c:30, d:8, e:12}
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56"])
var pie = d3.pie()
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(data))
svg
.selectAll('whatever')
.data(data_ready)
.enter()
.append('path')
.attr('d', normalArc)
.attr('fill', function(d){ return(color(d.data.key)) })
.style("opacity", 0.7)
.attr('d', function(d, index) {
// If this is the first segment make it a wider arc
if (index === 0) {
firstSelected = this;
return biggerArc(d);
} else {
return normalArc(d);
}
}).on("click", function(d) {
if (firstSelected) {
d3.select(firstSelected).attr("d", normalArc).style("stroke-width", "0px")
firstSelected = false;
}
if (lastSelected) {
d3.select(lastSelected).attr("d", normalArc).style("stroke-width", "0px")
}
d3.select(this).attr("d", biggerArc).style("stroke", "black").style("stroke-width", "10px")
.style("stroke-opacity","0.08")
.style('stroke-location',"outer")
.style('paint-order','stroke')
.style('stroke-linejoin',"round")
lastSelected = this;
})
</script>
</body>
</html>

After hours of searching i am able to find the answer. we need to create the filter for the drop shadow and append that to the svg and in which ever arc you want ,you just add the filter as an attribute
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title> D3 Js Example </title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
</head>
<body>
<div id="my_dataviz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.7/d3.min.js" ></script>
<script>
var lastSelected = "";
var firstSelected = "";
var width = 450
height = 450
margin = 40
var radius = Math.min(width, height) / 2 - margin
var normalArc = d3.arc().outerRadius(radius - 30).innerRadius(radius - 70);
var biggerArc = d3.arc().outerRadius(radius - 80).innerRadius(radius - 10);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
/* For the drop shadow filter... */
var defs = svg.append("defs");
var filter = defs.append("filter")
.attr("id", "dropshadow")
filter.append("feGaussianBlur")
.attr("in", "SourceAlpha")
.attr("stdDeviation", 4)
.attr("result", "blur");
filter.append("feOffset")
.attr("in", "blur")
.attr("dx", 2)
.attr("dy", 2)
.attr("result", "offsetBlur");
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode")
.attr("in", "offsetBlur")
feMerge.append("feMergeNode")
.attr("in", "SourceGraphic");
var data = {a: 9, b: 20, c:30, d:8, e:12}
var color = d3.scaleOrdinal()
.domain(data)
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56"])
var pie = d3.pie()
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(data))
svg
.selectAll('whatever')
.data(data_ready)
.enter()
.append('path')
.attr('d', normalArc)
.attr('fill', function(d){ return(color(d.data.key)) })
.style("opacity", 0.7)
.attr('d', function(d, index) {
// If this is the first segment make it a wider arc
if (index === 0) {
firstSelected = this;
return biggerArc(d);
} else {
return normalArc(d);
}
}).on("click", function(d) {
if (firstSelected) {
d3.select(firstSelected).attr("d", normalArc).attr("filter", "");
firstSelected = false;
}
if (lastSelected) {
d3.select(lastSelected).attr("d", normalArc).attr("filter", "");
}
d3.select(this).attr("d", biggerArc).attr("filter", "url(#dropshadow)");
lastSelected = this;
})
if(firstSelected){
d3.select(firstSelected).attr("filter", "url(#dropshadow)");
}
</script>
</body>
</html>

Related

d3 svg occluded by unknown element

I was trying to make a grid of rectangles for a heatmap. But for some reason, my rectangles are obstructed by an unknown element:
I thought I accidentally created a rectangle but failed to find it. Where does this white block come from?
Below is a simplified code snippet that demonstrates the same issue.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Graph</title>
<script src="https://d3js.org/d3.v4.js" charset='utf-8'></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js" charset='utf-8'></script>
<script src="https://d3js.org/d3.v4.min.js" charset='utf-8'></script>
</head>
<body>
<svg width="700" height="700" class="Q2">
</svg>
<script type='text/javascript'>
d3.csv("https://91063e21-7b3e-460b-9992-db5d8294e143.filesusr.com/ugd/00e35d_3ff25a705bf649108058b5fd0f8a0506.csv?dn=monthStateGen.csv", DrawGrid);
function DrawGrid(error, data) {
var maxValue = 65000000;
var squareSize = 50;
var squareGap = 5;
var squareBevel = 5;
var monthNum = 12;
var stateNum = 5;
var offsetX = 30;
var height = stateNum * (squareSize + squareGap)
var width = monthNum * (squareSize + squareGap)
var svg = d3.select(".Q2")
.append("svg")
.attr("width", squareSize)
.attr("height", height);
var states = d3.map(data, function(d){return d.STATE;}).keys();
var month = d3.map(data, function(d){return d.MONTH;}).keys();
var x = d3.scaleBand()
.range([ 0, width ])
.domain(month);
var y = d3.scaleBand()
.range([ 0, height])
.domain(states);
svg.selectAll()
.data(data)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.MONTH)+offsetX })
.attr("y", function(d) { return y(d.STATE) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", squareSize )
.attr("height", squareSize )
.attr('opacity', '0.8')
.style("fill", '#333' );
}
</script>
</body>
</html>
I've been changing a few things for you.
doctype
multiple d3 lib referencing
non-composing svg
the width of the svg, which should not only be the square size
<!DOCTYPE html>
<html>
<head>
<title>Graph</title>
<script src="https://d3js.org/d3.v4.min.js" charset='utf-8'></script>
</head>
<body>
<div class="Q2">
</div>
<script type='text/javascript'>
d3.csv("https://91063e21-7b3e-460b-9992-db5d8294e143.filesusr.com/ugd/00e35d_3ff25a705bf649108058b5fd0f8a0506.csv?dn=monthStateGen.csv", DrawGrid);
function DrawGrid(error, data) {
var squareSize = 50;
var squareGap = 5;
var squareBevel = 5;
var monthNum = 12;
var stateNum = 5;
var offsetX = 30;
var height = stateNum * (squareSize + squareGap)
var width = monthNum * (squareSize + squareGap)
var svg = d3.select(".Q2")
.append("svg")
.attr("width", width + (2 * offsetX))
.attr("height", height);
var states = d3.map(data, function(d){return d.STATE;}).keys();
var month = d3.map(data, function(d){return d.MONTH;}).keys();
var x = d3.scaleBand()
.range([ 0, width ])
.domain(month);
var y = d3.scaleBand()
.range([ 0, height])
.domain(states);
svg.selectAll()
.data(data)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.MONTH) +offsetX })
.attr("y", function(d) { return y(d.STATE) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", squareSize )
.attr("height", squareSize )
.attr('opacity', '0.8')
.style("fill", '#333' );
}
</script>
</body>
</html>

Pie chart not updating D3.JS

I know this question has been asked many times but I am not able to solve the problem of updating my pie chart. I am completely lost. Could you please tell me what seems to the problem here ?
I tried the following way but the chart doesn't seem to update. I added a function change that is supposed to update the chart. I am updating the data, redrawing the arcs and changing the labels but it is not working.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Load D3 -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="pie"></div>
<script>
var dataChart = { a: 9, b: 20, c: 30, d: 8, e: 12 };
var dataChart2 = { f: 9, g: 20, h: 30, i: 8 };
console.log(dataChart);
var width = 300,
height = 300,
// Think back to 5th grade. Radius is 1/2 of the diameter. What is the limiting factor on the diameter? Width or height, whichever is smaller
radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal()
.range(["#2C93E8", "#838690", "#F56C4E"]);
var pie = d3.pie()
.value(function (d) { return d.value; });
data = pie(d3.entries(dataChart));
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#pie")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // Moving the center point. 1/2 the width and 1/2 the height
var g = svg.selectAll("arc")
.data(data)
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d) { return color(d.data.key); });
g.append("text")
.attr("transform", function (d) { return "translate(" + labelArc.centroid(d) + ")"; })
.text(function (d) { return d.data.key; })
.style("fill", "#fff");
function change(dataChart) {
var pie = d3.pie()
.value(function (d) { return d.value; });
data = pie(d3.entries(dataChart));
path = d3.select("#pie").selectAll("path").data(data); // Compute the new angles
path.attr("d", arc); // redrawing the path
d3.selectAll("text").data(data).attr("transform", function (d) { return "translate(" + labelArc.centroid(d) + ")"; }); // recomputing the centroid and translating the text accordingly.
}
// calling the update functions
change(dataChart);
change (dataChart2);
</script>
</body>
</html>

D3 shape to follow path

Hi this is my first post. I've searched for a good tutorial to help finish this D3 line chart - but haven't found what I'm looking for. All I need to do is get the orange circle to follow the same path as the dotted line. At the moment it has a straight path. Thanks for any help on this.
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!-->
<html lang="en"><!--<![endif]-->
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Drawdown line chart</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
body {font: 15px sans-serif;}
.container{max-width:990px}
h2{float:left; width:100%; text-align:center; font-size:30px; color:#666666; margin:20px 0 30px}
.highlight{color:#f26522}
#chart{width:90%; margin:0 10%}
.domain {fill: none; stroke: gray; stroke-width: 1;}
</style>
</head>
<body>
<div class="container">
<h2>Click the <span class="highlight">orange dot</span> to start:</h2>
<div class="row">
<div id="chart" class="col-sm-12">
</div>
</div>
</div>
<script type="text/javascript">
// Chart data
var dataArray = [
{"x":0, "y":100000},
{"x":1, "y":90000},
{"x":2, "y":83000},
{"x":3, "y":73000},
{"x":4, "y":79000},
{"x":5, "y":72000},
{"x":6, "y":75000},
{"x":7, "y":88000},
{"x":8, "y":63000},
{"x":9, "y":71000},
{"x":10, "y":69000},
{"x":11, "y":63000},
{"x":12, "y":67000},
{"x":13, "y":63000},
{"x":14, "y":59000},
{"x":15, "y":46000},
{"x":16, "y":40000},
{"x":17, "y":32000},
{"x":18, "y":29000},
{"x":19, "y":20000},
{"x":20, "y":18000},
{"x":21, "y":17000},
{"x":22, "y":9000},
{"x":23, "y":0},
{"x":24, "y":0},
{"x":25, "y":0},
{"x":26, "y":0},
{"x":27, "y":0},
{"x":28, "y":0},
{"x":29, "y":0},
{"x":30, "y":0}
];
// Variables
var currentAge = 65
var longevity = 92
var yearsToLive = longevity - currentAge
var years = dataArray.length
var totalDrawdown = dataArray[0].y
var chartWidth = 800
var chartHeight = 400
var chartMargin = 20
var axisHeight = 20
var widthScale = d3.scale.linear()
.domain([currentAge, currentAge + years])
.range([0, chartWidth - chartMargin]);
var axis = d3.svg.axis()
.ticks(5)
.tickSize(20)
.scale(widthScale);
// Chart scaling
x_scale = d3.scale.linear().domain([0,years]).range([0, chartWidth]);
y_scale = d3.scale.linear().domain([0,totalDrawdown]).range([chartHeight - chartMargin,0]);
var lineFunction = d3.svg.line()
.x(function(d) { return x_scale(d.x) })
.y(function(d) { return y_scale(d.y) });
function getSmoothInterpolation() {
var interpolate = d3.scale.linear()
.domain([0,1])
.range([1, dataArray.length + 1]);
return function(t) {
var flooredX = Math.floor(interpolate(t));
var interpolatedLine = dataArray.slice(0, flooredX);
if(flooredX > 0 && flooredX < dataArray.length) {
var weight = interpolate(t) - flooredX;
var weightedLineAverage = dataArray[flooredX].y * weight + dataArray[flooredX-1].y * (1-weight);
interpolatedLine.push({"x":interpolate(t)-1, "y":weightedLineAverage});
}
return lineFunction(interpolatedLine);
}
}
// Canvas
var canvas = d3.select ("#chart")
.append("svg")
.attr("width", chartWidth)
.attr("height", chartHeight + axisHeight)
.attr("id", "lineChart");
// Longevity marker
var rectangle = canvas.append("rect")
.attr("width", (chartWidth/years) * ((currentAge + years) - longevity))
.attr("height", chartHeight - chartMargin)
.attr("x", (chartWidth/years) * (longevity - currentAge) )
.attr("fill","#f2f2f2");
// Destination range
var outer = canvas.append("rect")
.attr("width", 200)
.attr("height", 10)
.attr("x", 525 )
.attr("y", 380 )
.attr("fill","#f2f2f2");
var inner = canvas.append("rect")
.attr("width", 75)
.attr("height", 10)
.attr("x", 588 )
.attr("y", 380 )
.attr("fill","#d1d1d1");
var likely = canvas.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("x", 620 )
.attr("y", 380 )
.attr("fill","#666666");
// Chart path
canvas.append("path")
.attr("stroke-width", 2)
.attr("stroke", "gray")
.attr("fill", "none")
.attr("id", "journey")
.style("stroke-dasharray", ("3, 3"))
.attr("transform", "translate(" + chartMargin + ", 0)")
// Moving circle
var marker = canvas.append("circle")
.attr("id", "marker")
.attr("cx", 5 + chartMargin)
.attr("cy", 10)
.attr("r", 10)
.attr('fill', '#f26522');
// Add x axis
canvas.append("g")
.attr("transform", "translate("+ chartMargin + "," + (chartHeight - chartMargin) + ")")
.attr("fill","#aaaaaa")
.call(axis);
// Add start button
d3.select('#lineChart')
.append('circle')
.attr("cx", 5 + chartMargin)
.attr("cy", 10)
.attr("r", 10)
.attr('fill', '#f26522')
.on('click', function() {
d3.select('#lineChart > #journey')
.transition()
.duration(6000)
.attrTween('d', getSmoothInterpolation );
d3.select('#lineChart > #marker')
.transition()
.duration(6000)
.attrTween("cx", function (d, i, a) { return d3.interpolate(a, 620) })
.attrTween("cy", function (d, i, a) { return d3.interpolate(a, 400) });
});
</script>
</body>
</html>
Here is my try:
Instead of translating the circle via transition like this in the click function:
d3.select('#lineChart > #marker')
.transition()
.duration(6000)
.attrTween("cx", function (d, i, a) { return d3.interpolate(a, 620) })
.attrTween("cy", function (d, i, a) { return d3.interpolate(a, 400) });
Move the circle animation also with in the path animation like below:
function getSmoothInterpolation() {
var interpolate = d3.scale.linear()
.domain([0,1])
.range([1, dataArray.length + 1]);
return function(t) {
var flooredX = Math.floor(interpolate(t));
var interpolatedLine = dataArray.slice(0, flooredX);
if(flooredX > 0 && flooredX < dataArray.length) {
var weight = interpolate(t) - flooredX;
var weightedLineAverage = dataArray[flooredX].y * weight + dataArray[flooredX-1].y * (1-weight);
interpolatedLine.push({"x":interpolate(t)-1, "y":weightedLineAverage});
//get the length of the path
var len = d3.select("#journey").node().getTotalLength();
//get the svg point at that length
var pt = d3.select("#journey").node().getPointAtLength(len);
//translate the circle to that point.
d3.select('#lineChart > #marker').attr("transform", "translate(" +pt.x + "," + pt.y + ")");
}
return lineFunction(interpolatedLine);
}
}
working code here

html file + d3.js script file + input data manually in html file

I am new in d3.js language. I am trying to built a simple application but I stuck some where. I have a separate .js file jack.js which makes pie chart when you link it with html page.
Problem I want to use that file in every html page with different data. But i cant find the perfect solution of this. whenever page loaded in browser, file load its pie chart visualization. So can you suggest me what should i need to do?
HTML page
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="lib/pie.js"></script>
<script>
dataset = [1,2,3,4,5];
</script>
</head>
<body>
</body>
</html> `
jack.js
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
<body>
<script type="text/javascript" src="lib/pie.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</body>
This way you can do this.
Hi Remove var dataset = [ 5, 10, 20, 45, 6, 25 ]; from jack.js and put them either in your html file like you did in the head of your html file. Call jack.js in the body.
This will ensure that the data is loaded first before jack.js.
Hence your code will look like this
Html
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</head>
<body>
<script type="text/javascript" src="lib/pie.js"></script>
</body>
</html>
pie.js
var w = 300;
var h = 300;
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
Alternatively, you place wrap you d3 code in a $( document ).ready( //your d3 code here ) http://learn.jquery.com/using-jquery-core/document-ready/
Alternatively
pie.js
$( document ).ready(
// d3 code here
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
....
)

How to make seperate file of d3.js pie chart and load it to html page

I pasted that code to jack.js file
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
var color = d3.scale.category10();
var svg = d3.select("body").append("svg").attr("width", w)
.attr("height", h);
var arcs = svg.selectAll("g.arc").data(pie(dataset)).enter()
.append("g").attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," +outerRadius + ")");
arcs.append("path").attr("fill", function(d, i) {
return color(i);})
.attr("d", arc).on("mouseenter", function(d) {
//console.log("mousein")
text = arcs.append("text").attr("transform", arc.centroid(d))
.attr("dy", ".5em").style("text-anchor", "middle")
.style("fill", "blue").attr("class", "on")
.text(d.data.place);})
.on("mouseout", function(d) {
text.remove();});
//Labels
arcs.append("text").attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")"; })
.attr("text-anchor", "middle").text(function(d) {
return d.value;
});</script>
and linked it to my html page.
Problem: This jack.js file is not showing pie chart in HTML page. can any body suggest me what should I need to do?
Is this the behavior you wanted?
plnkr
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script type="text/javascript" src="jack.js"></script>
<h1>Hello Plunker!</h1>
</body>
</html>

Categories