Built with blockbuilder.org
forked from Kashif1Naqvi's block: Donut Chart(Budget Planner)
forked from Kashif1Naqvi's block: Donut Chart(Budget Planner)
license: mit |
Built with blockbuilder.org
forked from Kashif1Naqvi's block: Donut Chart(Budget Planner)
forked from Kashif1Naqvi's block: Donut Chart(Budget Planner)
const dim = { width:500 , height: 340, radius:150 } | |
const cent = {x:dim.width/2 + 5 , y:dim.height/2 + 5 } | |
const svg = d3.select(".canvas").append("svg").attr("height",dim.height+150).attr("width",dim.width+150) | |
const graph = svg.append("g").attr("transform",`translate(${cent.x},${cent.y})`) | |
const color = d3.scaleOrdinal(d3['schemeSet3']) | |
const pie = d3.pie().sort(null).value(d=>d.cost) | |
const arcPath = d3.arc().outerRadius(dim.radius).innerRadius(dim.radius/2) | |
const legendGroup = svg.append("g").attr("transform",`translate(${cent.x + 190},${cent.y-101})`) | |
const legend = d3.legendColor() | |
.shape("circle") | |
.shapePadding(10) | |
.scale(color); | |
const tip = d3.tip() | |
.attr("class","tip card") | |
.html(d=>{ | |
let content = `<div class="name" >${d.data.name}</div>` | |
content += `<div class="cost">${d.data.cost}</div>` | |
content += `<div class="text-info">Click slice to delete</div>` | |
return content; | |
}) | |
graph.call(tip) | |
var data = [] | |
const update = (data) => { | |
color.domain(data.map(d => d.name)) | |
legendGroup.call(legend).style("fill","#fff").style("font-weight","bold") | |
const path = graph.selectAll("path").data(pie(data)) | |
path.exit().transition().duration(750).attrTween("d",arcTweenExit) | |
.remove() | |
path.attr("d",arcPath) | |
.enter() | |
.append("path") | |
.attr("stroke","#fff") | |
.attr("stroke-width",1) | |
.attr("fill", d => color(d.data.name)) | |
graph.selectAll("path") | |
.on("mouseover",(d,i,n)=>{ | |
tip.show(d,n[i]) | |
handleMouseOver(d,i,n) | |
}) | |
.on("mouseout",(d,i,n)=>{ | |
tip.hide() | |
handleMouseOut(d,i,n) | |
}) | |
.on("click",handleClick) | |
.transition() | |
.duration(750) | |
.attrTween("d",arcTweenEnter) | |
} | |
db.collection("expenses").onSnapshot(res=>{ | |
console.log(res); | |
res.docChanges().map(change=>{ | |
let doc = {...change.doc.data(), id: change.doc.id} | |
switch (change.type) { | |
case 'added': | |
data.push(doc) | |
break; | |
case 'modified': | |
let index = data.findIndex(item => item.id == doc.id ); | |
data[index] = doc; | |
break; | |
case "removed": | |
data = data.filter(item => item.id !== doc.id) | |
break; | |
default: | |
break; | |
} | |
}) | |
update(data) | |
}) | |
const arcTweenEnter = (d) => { | |
let i = d3.interpolate(d.endAngle , d.startAngle); | |
return function(t){ | |
d.startAngle = i(t) | |
return arcPath(d) | |
} | |
} | |
const arcTweenExit = (d) => { | |
let i = d3.interpolate(d.startAngle , d.endAngle); | |
return function(t){ | |
d.startAngle = i(t) | |
return arcPath(d) | |
} | |
} | |
const handleMouseOver = (d,i,n)=>{ | |
d3.select(n[i]).transition("changeSliceFill").duration(400).attr("fill","white") | |
} | |
const handleMouseOut = (d,i,n)=>{ | |
d3.select(n[i]).transition("changeSliceFill").duration(400).attr("fill",color(d.data.name)) | |
} | |
const handleClick = (d) =>{ | |
console.log(d.data.id); | |
let id = d.data.id | |
db.collection("expenses").doc(id).delete() | |
} |
<!DOCTYPE html> | |
<html lang="en" dir="ltr"> | |
<head> | |
<meta charset="utf-8"> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> | |
<title>Dont charset</title> | |
</head> | |
<body class="bg-dark" > | |
<style> | |
.text-line { | |
background-color: transparent; | |
color: #000; | |
outline: none; | |
outline-style: none; | |
border-top: none; | |
border-left: none; | |
border-right: none; | |
border-bottom: solid #eeeddd 2px; | |
padding: 13px 13px; | |
} | |
.tip { | |
pointer-events:none; | |
position:absolute; | |
margin:1px; | |
padding-bottom: : 5px; | |
opacity: .9; | |
padding:0px; | |
background: none repeat scroll 0 white; | |
border:solid none; | |
box-shadow: 0px 3px 15px #888888; | |
color:#8f8e8c; | |
font: 14px sans-serif; | |
width:100px; | |
height:inherit; | |
text-align: center; | |
font-weight: normal; | |
border-radius: 3px; | |
/* font-family: 'Staatliches', cursive; */ | |
font-family: 'Liu Jian Mao Cao', cursive; | |
font-family: 'Courgette', cursive; | |
} | |
.tip ::after { | |
content: ""; | |
position: absolute; | |
top: 100%; | |
left: 80%; | |
margin-left:-35px; | |
border-width:10px; | |
border-style: solid; | |
border-color: white transparent transparent transparent; | |
} | |
</style> | |
<div class="container" > | |
<header class="bg-light" > | |
<h2 class="text-center p-4" >Tracker</h2> | |
<p class="text-center p-4" >Monthly Money Tracker</p> | |
</header> | |
<div class="row"> | |
<div class="col-12 col-sm-6 col-lg-6 col-md-6 col-xl-6"> | |
<form class="card p-3 m-4" > | |
<div class="card-body" > | |
<div class="form-group" > | |
<label for="name"></label> | |
<input type="text" class="text-line" placeholder="Name" id="name"> | |
</div> | |
<div class="form-group"> | |
<label for="cost"></label> | |
<input type="text" id="cost" class="text-line" placeholder="Cost" > | |
</div> | |
<p id="error" class="alert-danger mt-3"></p> | |
<input type="submit" value="Add item" class="btn btn-danger float-right " style="border-style:dashed;" > | |
</div> | |
</form> | |
</div> | |
<div class="col-12 col-sm-6 col-lg-6 col-md-6 col-xl-6"> | |
<div class="canvas" ></div> | |
</div> | |
</div> | |
</div> | |
<!-- The core Firebase JS SDK is always required and must be listed first --> | |
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js"></script> | |
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-firestore.js"></script> | |
<!-- TODO: Add SDKs for Firebase products that you want to use | |
https://firebase.google.com/docs/web/setup#available-libraries --> | |
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-analytics.js"></script> | |
<script> | |
// Your web app's Firebase configuration | |
var firebaseConfig = { | |
apiKey: "AIzaSyCrJwDOd-Fu8R9i2NFTuk3adl49_5bdMME", | |
authDomain: "d3-firebase-1c3d6.firebaseapp.com", | |
databaseURL: "https://d3-firebase-1c3d6.firebaseio.com", | |
projectId: "d3-firebase-1c3d6", | |
storageBucket: "d3-firebase-1c3d6.appspot.com", | |
messagingSenderId: "776696333178", | |
appId: "1:776696333178:web:04004dafee1c4dace4ccc3", | |
measurementId: "G-9X0E1CZWNF" | |
}; | |
// Initialize Firebase | |
firebase.initializeApp(firebaseConfig); | |
firebase.analytics(); | |
let db = firebase.firestore() | |
</script> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.6/d3-legend.min.js" ></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script> | |
<script src="index.js" ></script> | |
<script src="graph.js" ></script> | |
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> | |
</body> | |
</html> |
let form = document.querySelector("form") | |
let name = document.querySelector("#name") | |
let cost = document.querySelector("#cost") | |
let error = document.querySelector("#error") | |
form.addEventListener("submit",(e)=>{ | |
e.preventDefault(); | |
if(name.value && cost.value ){ | |
let item = { | |
name : name.value, | |
cost: parseInt(cost.value) | |
} | |
db.collection('expenses').add(item).then(res=>{ | |
name.value = "" | |
cost.value = "" | |
error.textContent = "" | |
} | |
) | |
}else{ | |
error.textContent = "Please enter values before submitting" | |
} | |
}) |