Published
Edited
Apr 30, 2021
Insert cell
Insert cell
percentPlayed = {
let naColor = "#C33C54"
let euColor = "#4D8EA7"
let svg = d3.create('svg').style("background-color", 'white').attr("preserveAspectRatio", "none").style("background-color", 'white').attr("viewBox", "0 0 1150 650");

let viperColor = "#1ab963"
svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 2)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: 20px; font-family: 'Bebas Neue';")
.text("Author: Sam Rosenberg").call(addWebFont, 'Bebas Neue', 'https://fonts.gstatic.com/s/bebasneue/v2/JTUSjIg69CK48gW7PXoo9WlhyyTh89Y.woff2').attr('style', d => "font-size: 20px; font-family: 'Bebas Neue';");

svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 480)
.attr("x", 1008)
.attr("dy", ".75em")
.attr('style', "font-size: 30px; font-family: 'Bebas Neue';")
.text("Image from valorant.fandom.com").attr('style', d => "font-size: 19px; font-family: 'Bebas Neue';");

svg.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', 140)
.attr('height', 40)
.attr('stroke', 'black')
.attr('fill', 'black');
svg.append("image")
.attr("xlink:href", "https://runitback.gg/static/media/logo.dcfad9c9.png")
.attr("x", 10)
.attr("y", -10)
.attr("width", 120)
.attr("height", 60);

svg.append("image")
.attr("xlink:href", "https://greblytics.com/wp-content/uploads/2021/04/viper.png")
.attr("x", 810)
.attr("y", 0)
.attr("width", 400)
.attr("height", 480);

var text2 = svg.append("svg:text").attr("class", "title")
.attr("xlink:href", "greblytics.com")
.attr("text-anchor", "middle")
.attr("y", 60)
.attr("x", 963/2)
.attr('style', "font-size: 45px; font-family: 'Bebas Neue';");
;
text2.append("svg:tspan").style("fill", euColor).text("Europe");
text2.append("svg:tspan").style("fill", "black").text(" vs. ");
text2.append("svg:tspan").style("fill", naColor).text("North America ");
text2.append("svg:tspan").style("fill", "black").text("Viper")
text2.append("svg:tspan").style("fill", "black").text(" Pickrates");

let viperX = d3.scaleOrdinal()
.domain(["", "S1C1", "S1C2", "S1C3", "S1M", "S2C1", "S2C2"])
.range([50, 100, 250, 400, 550, 700, 850].map(d=> d*0.95 + 30))

let viperXAxis = d3.scaleOrdinal()
.domain(["", "Stage 1: Challengers 1", "Stage 1: Challengers 2", "Stage 1: Challengers 3", "Stage 1: Masters", "Stage 2: Challengers 1", "Stage 2: Challengers 2"])
.range([21, 100, 250, 400, 550, 700, 850].map(d=> d*0.95 + 30))

let viperY = d3.scaleLinear()
.domain([-2,30])
.range([450, 80])

const line = d3.line()
.x(function(d) {return d[0];})
.y(function(d) {return d[1];})

let data = []
for (let i = 0; i < Object.keys(euVipers).length; i++)
{
/*let toAdd = {}
toAdd["x"] = Object.keys(euVipers)[i]
toAdd["y"] = euVipers[Object.keys(euVipers)[i]]
data.push(toAdd)
*/
data.push([viperX(Object.keys(euVipers)[i]), viperY(euVipers[Object.keys(euVipers)[i]])])
}
console.log(data)
d3.select('svg')
.append('path') // add a path to the existing svg
.datum(data)
.attr('d', line)
.attr('stroke', 'black')

/*
.on('mouseover', function(event, d) {
d3.select('#nameText').text(d['Name']);
let loc = d3.pointer(event);
d3.select('#nameText').attr('x', loc[0]);
d3.select('#nameText').attr('y', loc[1]-13);
})
*/
for (let i = 0; i < Object.keys(euVipers).length-1; i++)
{
let xOld = viperX(Object.keys(euVipers)[i])
let yOld = viperY(euVipers[Object.keys(euVipers)[i]])
let xNew = viperX(Object.keys(euVipers)[i+1])
let yNew = viperY(euVipers[Object.keys(euVipers)[i+1]])
svg.append("line").attr("x1", xOld).attr("y1", yOld).attr("x2", xNew).attr("y2", yNew).attr("stroke", euColor).attr("stroke-width", 3)
}

for (let i = 0; i < Object.keys(naVipers).length-1; i++)
{
let xOld = viperX(Object.keys(naVipers)[i])
let yOld = viperY(naVipers[Object.keys(naVipers)[i]])
let xNew = viperX(Object.keys(naVipers)[i+1])
let yNew = viperY(naVipers[Object.keys(naVipers)[i+1]])
svg.append("line").attr("x1", xOld).attr("y1", yOld).attr("x2", xNew).attr("y2", yNew).attr("stroke", naColor).attr("stroke-width", 3)
}

for (let i = 0; i < Object.keys(euVipers).length; i++)
{
svg.append("circle")
.attr("cx", viperX(Object.keys(euVipers)[i]))
.attr("cy", viperY(euVipers[Object.keys(euVipers)[i]]))
.attr("r", 5).attr("fill", euColor)
}

for (let i = 0; i < Object.keys(naVipers).length; i++)
{
svg.append("circle")
.attr("cx", viperX(Object.keys(naVipers)[i]))
.attr("cy", viperY(naVipers[Object.keys(naVipers)[i]]))
.attr("r", 5).attr("fill", naColor)
}


for (let i = 0; i < Object.keys(naVipers).length; i++)
{
svg.append("rect")
.attr("x", viperX(Object.keys(naVipers)[i])-80)
.attr("y", 80)
.attr("width", 160)
.attr("height", 370)
.attr("fill", 'transparent')
.on('mouseover', function(event, d) {
d3.select(this).attr('fill', "grey").attr('opacity', 0.2);
let selectedEventVipers = NAPlayers[Object.keys(NAPlayers)[i]].filter(d => d.Agent === "Viper")
drawTeamLogosNA(selectedEventVipers)
let selectedEventVipersEU = EUPlayers[Object.keys(EUPlayers)[i]].filter(d => d.Agent === "Viper")
drawTeamLogosEU(selectedEventVipersEU)
})
.on('mouseout', function(event, d) {
d3.select(this).attr('fill', "transparent");
console.log(event)
})
}
//svg.append("line").attr("x1", xOld).attr("y1", yOld).attr("x2", xNew).attr("y2", yNew).attr("stroke", naColor).attr("stroke-width", 3)

let boxWidth = 100;
function drawTeamLogosEU(selectedEventVipers)
{
for (let i = 0; i < selectedEventVipers.length; i++)
{
console.log(selectedEventVipers[i])
svg.append("rect")
.attr("x", 1090 - i*boxWidth - boxWidth/2)
.attr("y", 505)
.attr("width", boxWidth)
.attr("height", boxWidth+35)
.attr("fill", euColor).attr("opacity", 0.4)
.attr("stroke-thickness", 3).attr("stroke", "black")

svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 530)
.attr("x", 1090 - i*boxWidth)
.attr('style', "font-size: 50px; font-family: 'Bebas Neue';")
.text(selectedEventVipers[i]["Ign"]).attr('style', d => "font-size: 30px; font-family: 'Bebas Neue';");
svg.append("image")
.attr("xlink:href", teamLogos[selectedEventVipers[i]["Team"]])
.attr("x", 1090 - i*boxWidth - boxWidth/2)
.attr("y", 540)
.attr("width", boxWidth)
.attr("height", boxWidth);
}
}




function drawTeamLogosNA(selectedEventVipers)
{
svg.append("rect")
.attr("x", 0)
.attr("y", 500)
.attr("width", 1150)
.attr("height", 300)
.attr("fill", 'white')
for (let i = 0; i < selectedEventVipers.length; i++)
{
console.log(selectedEventVipers[i])
svg.append("rect")
.attr("x", 60 + i*boxWidth - boxWidth/2)
.attr("y", 505)
.attr("width", boxWidth)
.attr("height", boxWidth+35)
.attr("fill", naColor).attr("opacity", 0.4)
.attr("stroke-thickness", 3).attr("stroke", "black")

svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 530)
.attr("x", 60 + i*boxWidth)
.attr('style', "font-size: 50px; font-family: 'Bebas Neue';")
.text(selectedEventVipers[i]["Ign"]).attr('style', d => "font-size: 30px; font-family: 'Bebas Neue';");
svg.append("image")
.attr("xlink:href", teamLogos[selectedEventVipers[i]["Team"]])
.attr("x", 60 + i*boxWidth - boxWidth/2)
.attr("y", 540)
.attr("width", boxWidth)
.attr("height", boxWidth);
}
}
svg.append('g')
.attr('transform', `translate(${50}, 0)`)
.call(d3.axisLeft(viperY).tickFormat(function(d) { return d + "%"})).attr('style', d => "font-size: 20px; font-family: 'Bebas Neue';");
svg.append('g')
.attr('transform', `translate(0, ${450})`)
.call(d3.axisBottom(viperXAxis)).attr('style', d => "font-size: 15px; font-family: 'Bebas Neue';");

return svg.node();
}
Insert cell
teamLogos = {
return {"Sentinels" : "https://owcdn.net/img/5f25fa763f7ad.png", "Envy" : "https://owcdn.net/img/5f3ca822464a3.png", "TSM": "https://owcdn.net/img/5f3ca6f653a9c.png", "Immortals" : "https://owcdn.net/img/602e1b45e079f.png", "FaZe": "https://owcdn.net/img/5ef51451b0601.png", "100 Thieves" : "https://owcdn.net/img/603c00d5c5a08.png", "LG": "https://owcdn.net/img/5f36ec1f4ab21.png", "Andbox (ex)":"https://owcdn.net/img/5f64213a6402f.png", "Cloud9 Blue": "https://owcdn.net/img/60135aa861fc5.png", "XSET": "https://owcdn.net/img/5f9725636681d.png", "GEN": "https://owcdn.net/img/5f308c5756db6.png", "NRG": "https://owcdn.net/img/5f7b9ff821d6d.png", "T1":"https://owcdn.net/img/5ea85d21e625f.png", "Built By Gamers":"https://owcdn.net/img/5f88bd58c0630.png", "Andbox":"https://owcdn.net/img/5f64213a6402f.png", "Immortals (si)" : "https://owcdn.net/img/602e1b45e079f.png", "Team Liquid": "https://owcdn.net/img/5f11fac202eeb.png", "Acend":"https://owcdn.net/img/604a83800fa73.png", "Team Vitality":"https://owcdn.net/img/5efe491dd8181.png", "Fnatic":"https://owcdn.net/img/603c0453b0cd2.png", "FunPlus Phoenix":"https://owcdn.net/img/5feab33100c1d.png", "Ninjas in Pyjamas":"https://owcdn.net/img/600f8bbf4603f.png", "Guild Esports":"https://owcdn.net/img/5f901f417a773.png", "Team Heretics":"https://owcdn.net/img/5f91e71607511.png", "Ballista Esports":"https://owcdn.net/img/602974130c5c5.png", "G2 Esports":"https://owcdn.net/img/5f3cbb213e5de.png", "Monkey Business (ex)":"https://owcdn.net/img/601dad9359d35.png", "Wave Esports":"https://owcdn.net/img/60305cb6c16c7.png", "Alliance": "https://owcdn.net/img/6012ec3dde855.png", "Raise Your Edge Gaming (ex)":"https://owcdn.net/img/601568bab77e9.png"}
}
Insert cell
EU = { return {"S2C2": await FileAttachment("EU S2 C2.csv").csv(), "S2C1": await FileAttachment("EU S2 C1.csv").csv(), "S1M": await FileAttachment("EU S1 M.csv").csv(), "S1C3": await FileAttachment("EU S1 C3.csv").csv(), "S1C2": await FileAttachment("EU S1 C2.csv").csv(), "S1C1": await FileAttachment("EU S1 C1.csv").csv()}}
Insert cell
EUPlayers = { return {"S2C2": await FileAttachment("EU S2 C2 Players.csv").csv(), "S2C1": await FileAttachment("EU S2 C1 Players.csv").csv(), "S1M": await FileAttachment("EU S1 M Players.csv").csv(), "S1C3": await FileAttachment("EU S1 C3 Players.csv").csv(), "S1C2": await FileAttachment("EU S1 C2 Players.csv").csv(), "S1C1": await FileAttachment("EU S1 C1 Players.csv").csv()}}
Insert cell
NA = { return {"S2C2": await FileAttachment("NA S2 C2.csv").csv(), "S2C1": await FileAttachment("NA S2 C1.csv").csv(), "S1M": await FileAttachment("NA S1 M.csv").csv(), "S1C3": await FileAttachment("NA S1 C3.csv").csv(), "S1C2": await FileAttachment("NA S1 C2.csv").csv(), "S1C1": await FileAttachment("NA S1 C1.csv").csv()}}
Insert cell
NAPlayers = { return {"S2C2": await FileAttachment("NA S2 C2 Players.csv").csv(), "S2C1": await FileAttachment("NA S2 C1 Players.csv").csv(), "S1M": await FileAttachment("NA S1 M Players.csv").csv(), "S1C3": await FileAttachment("NA S1 C3 Players.csv").csv(), "S1C2": await FileAttachment("NA S1 C2 Players.csv").csv(), "S1C1": await FileAttachment("NA S1 C1 Players.csv").csv()}}
Insert cell
Object.keys(EU)[1]
Insert cell
euVipers = getVipersEU()
Insert cell
function getVipersEU(){
let toReturn = {}
for (let i = 0; i < Object.keys(EU).length; i++)
{
toReturn[Object.keys(EU)[i]] = EU[Object.keys(EU)[i]].filter(d => d["Agent"] === "Viper")[0]["Percentage"]
}
return toReturn
}
Insert cell
Insert cell
function getVipersNA(){
let toReturn = {}
for (let i = 0; i < Object.keys(NA).length; i++)
{
if (NA[Object.keys(NA)[i]].filter(d => d["Agent"] === "Viper")[0] !== undefined)
{
toReturn[Object.keys(NA)[i]] = NA[Object.keys(NA)[i]].filter(d => d["Agent"] === "Viper")[0]["Percentage"]
}
else
{
toReturn[Object.keys(NA)[i]] = 0
}
}
return toReturn
}
Insert cell
d3 = require('d3@v6')
Insert cell
async function toDataURL(url) {
return new Promise(async(resolve, reject) => {
const res = await fetch(url);
if(!res.ok) return reject(`Error: ${res.status} ${res.statusText}`);
const blob = await res.blob();
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.result);
});
}
Insert cell
async function addWebFont(selection, fontName, fontURL, fontType = 'woff2') {
const fontData = await toDataURL(fontURL);
return selection.append('style').text(`
@font-face {
font-family: '${fontName}';
src: url(${fontData}) format('${fontType}');
}
`);
};
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more