//Global variable declaration //Site data so you only have to load it one time var siteData; var entitiesOrInterests = 'entities'; //Donald Trump, Elon Musk, etc. var currentEntity; //Trends, Linguistics, Entities, Geography var currentView; //1 year ago, 1 month ago, 1 week ago var currentTimeFrame; //Subdata views for each current view var currentDataView; var trendsChart; var wordCloud; var myWordsCached; var globalMap = null; var topicChart //entityCardOptions var entityCardOptions = { showPoint: false, showLine: true, showArea: false, fullWidth: false, showLabel: false, axisX: { showGrid: false, showLabel: true, }, axisY: { showGrid: false, showLabel: false, }, chartPadding: 2, low: 0 }; //Global options for each of the chartist trends charts var options = { showPoint: false, showLine: true, showArea: false, fullWidth: false, showLabel: true, axisX: { showGrid: false, showLabel: false, }, axisY: { showGrid: false, showLabel: false, }, chartPadding: 2, low: 0 }; //chartJS options var chartJSOptions = { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day', }, grid: { display: false, }, title: { display: true, text: 'Date' } }, y: { grid: { display: false, }, title: { display: true, text: 'Net Appearance' } } }, plugins: { tooltip: { enabled: false } } } function buildTrendsChart(ctx, data, datatype) { if (datatype == 'universe') { chartJSOptions['scales']['y']['title']['text'] = "Net Appearance"; var tempChart = new Chart(ctx, { type: 'line', // Specify the chart type (e.g., bar, line, pie, etc.) data: { labels: data.labels, datasets: [{ label: 'Universe', data: data.series[0], backgroundColor: '#22aaff', borderColor: '#22aaff', borderWidth: 3, pointRadius: 0, lineTension:.25, }] }, options: chartJSOptions }); } if (datatype == 'sentiment') { chartJSOptions['scales']['y']['title']['text'] = "Net Sentiment"; var tempChart = new Chart(ctx, { type: 'line', // Specify the chart type (e.g., bar, line, pie, etc.) data: { labels: data.labels, datasets: [{ label: 'Positive', data: data.series[0], backgroundColor: '#88dd11', borderColor: '#88dd11', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Negative', data: data.series[1], backgroundColor: '#ff3366', borderColor: '#ff3366', borderWidth: 3, pointRadius: 0, lineTension:.25, }, ] }, options: chartJSOptions }); } if (datatype == 'emotions') { chartJSOptions['scales']['y']['title']['text'] = "Percentage (%) of Collected Posts"; var tempChart = new Chart(ctx, { type: 'line', // Specify the chart type (e.g., bar, line, pie, etc.) data: { labels: data.labels, datasets: [{ label: 'Trust', data: data.series[0], backgroundColor: '#22aaff', borderColor: '#22aaff', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Joy', data: data.series[1], backgroundColor: '#22dddd', borderColor: '#22dddd', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Love', data: data.series[2], backgroundColor: '#88dd11', borderColor: '#88dd11', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Anticipation', data: data.series[3], backgroundColor: '#ffdd00', borderColor: '#ffdd00', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Surprise', data: data.series[4], backgroundColor: '#ff9922', borderColor: '#ff9922', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Anger', data: data.series[5], backgroundColor: '#ff3366', borderColor: '#ff3366', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Fear', data: data.series[6], backgroundColor: '#ee44ee', borderColor: '#ee44ee', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Hate', data: data.series[7], backgroundColor: '#aa77ff', borderColor: '#aa77ff', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Disgust', data: data.series[8], backgroundColor: '#ccaa66', borderColor: '#ccaa66', borderWidth: 3, pointRadius: 0, lineTension:.25, }, { label: 'Sadness', data: data.series[9], backgroundColor: '#8899bb', borderColor: '#8899bb', borderWidth: 3, pointRadius: 0, lineTension:.25, }, ] }, options: chartJSOptions }); } return tempChart; } //code that handles view switching (Trends, Linguistics, etc.) function handleViewButtonSelection() { const buttons = document.querySelectorAll('.view-button'); const views = document.querySelectorAll('.view'); // Add 'active' class to the first button and its corresponding view buttons[0].classList.add('active'); const defaultViewId = buttons[0].getAttribute('id').replace('button', 'view'); const defaultView = document.getElementById(defaultViewId); defaultView.classList.add('active'); buttons.forEach(button => { button.addEventListener('click', () => { // Remove 'active' class from all buttons and views buttons.forEach(btn => btn.classList.remove('active')); views.forEach(view => view.classList.remove('active')); // Add 'active' class to the clicked button and corresponding view button.classList.add('active'); const targetViewId = button.getAttribute('id').replace('button', 'view'); const targetView = document.getElementById(targetViewId); targetView.classList.add('active'); const timeButtons = document.querySelectorAll('.time-button'); timeButtons.forEach(btn => btn.classList.remove('active')); const activeTimeButtons = document.querySelectorAll('.view.active')[0].querySelectorAll('.time-button'); activeTimeButtons[0].classList.add('active'); currentTimeFrame = activeTimeButtons[0].textContent.toLowerCase(); const activeDataButtons = document.querySelectorAll('.view.active')[0].querySelectorAll('.data-button'); activeDataButtons.forEach(btn => btn.classList.remove('active')); activeDataButtons[0].classList.add('active'); currentDataView = activeDataButtons[0].textContent.toLowerCase(); currentView = button.textContent.toLowerCase(); if (currentView == "trends") { var newData = buildChartData(siteData['key'][entitiesOrInterests][currentEntity], currentView, currentTimeFrame, currentDataView) //trendsChart.update(newData); var newData = buildChartData(siteData['key'][entitiesOrInterests][currentEntity], currentView, currentTimeFrame, currentDataView) trendsChart.destroy(); var ctx = document.getElementById('ct-chart-trends').getContext('2d'); trendsChart = buildTrendsChart(ctx, newData, currentDataView); } if (currentView =='linguistics') { var words = siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView] wordCloud = drawWordCloud(words) } if ((currentView == 'geography') && (globalMap == null)) { globalMap = drawMap("map", siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView]); } else if ((currentView == 'geography') && (globalMap != null)){ globalMap = updateMap("map", globalMap, siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView]); } }); }); } //code that handles time frame switching function handleTimeButtonSelection() { const buttons = document.querySelectorAll('.time-button'); const views = document.querySelectorAll('.time'); // Add 'active' class to the first button and its corresponding view buttons[0].classList.add('active'); const defaultViewId = buttons[0].getAttribute('id').replace('button', 'view'); const defaultView = document.getElementById(defaultViewId); defaultView.classList.add('active'); buttons.forEach(button => { button.addEventListener('click', () => { // Remove 'active' class from all buttons and views buttons.forEach(btn => btn.classList.remove('active')); views.forEach(view => view.classList.remove('active')); // Add 'active' class to the clicked button and corresponding view button.classList.add('active'); currentTimeFrame = button.textContent; if (currentView == "trends") { var newData = buildChartData(siteData['key'][entitiesOrInterests][currentEntity], currentView, currentTimeFrame, currentDataView) trendsChart.destroy(); var ctx = document.getElementById('ct-chart-trends').getContext('2d'); trendsChart = buildTrendsChart(ctx, newData, currentDataView); } if (currentView =='linguistics') { var words = siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView] wordCloud = drawWordCloud(words) } if (currentView == 'geography') { globalMap = updateMap("map", globalMap, siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView]); } }); }); } //This function handles the button selection and allows users to select various tabs within each entity subpage function handleDataButtonSelection() { const buttons = document.querySelectorAll('.data-button'); const views = document.querySelectorAll('.data'); // Add 'active' class to the first button and its corresponding view buttons[0].classList.add('active'); const defaultViewId = buttons[0].getAttribute('id').replace('button', 'view'); const defaultView = document.getElementById(defaultViewId); defaultView.classList.add('active'); buttons.forEach(button => { button.addEventListener('click', () => { // Remove 'active' class from all buttons and views buttons.forEach(btn => btn.classList.remove('active')); views.forEach(view => view.classList.remove('active')); // Add 'active' class to the clicked button and corresponding view button.classList.add('active'); currentDataView = button.textContent.toLowerCase(); if (currentView == "trends") { var newData = buildChartData(siteData['key'][entitiesOrInterests][currentEntity], currentView, currentTimeFrame, currentDataView) trendsChart.destroy(); var ctx = document.getElementById('ct-chart-trends').getContext('2d'); trendsChart = buildTrendsChart(ctx, newData, currentDataView); } if (currentView =='linguistics') { var words = siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView] wordCloud = drawWordCloud(words) if (currentDataView == 'mentions') { document.getElementById("linguistics-info-box").innerHTML = "Sentiment"; document.getElementById("linguistics-color-gradient").className = "color-gradient-sentiment"; } else if (currentDataView == 'topics') { document.getElementById("linguistics-info-box").innerHTML = "Sentiment"; document.getElementById("linguistics-color-gradient").className = "color-gradient-sentiment"; } else if (currentDataView == 'hashtags') { document.getElementById("linguistics-info-box").innerHTML = "Sentiment"; document.getElementById("linguistics-color-gradient").className = "color-gradient-sentiment"; } } if (currentView == 'geography') { globalMap = updateMap("map", globalMap, siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView]); if (currentDataView == 'universe') { document.getElementById("geography-info-box").innerHTML = "Universe"; document.getElementById("geography-color-gradient").className = "color-gradient-universe"; } else if (currentDataView == 'sentiment') { document.getElementById("geography-info-box").innerHTML = "Sentiment"; document.getElementById("geography-color-gradient").className = "color-gradient-sentiment"; } else if (currentDataView == 'trust score') { document.getElementById("geography-info-box").innerHTML = "Trust Score"; document.getElementById("geography-color-gradient").className = "color-gradient-score"; } } }); }); } //This function inserts the infegy branding logo to each title card (depending on where you need it) function insertInfegyLightbulbLogo(imageName) { urlPath = "https://1716283.fs1.hubspotusercontent-na1.net/hubfs/1716283/Top_Brands_2024_Refresh/logos/" const image = document.createElement('img') image.classList.add("imgLogo") image.src = urlPath+imageName+".png" image.alt = 'Image alt' return image; } //This bit of code reads the entity summary from the json and puts it in the entity card along with the image function createEntityNameSummary(data, box, i) { // Create the name element const name = document.createElement('h2'); name.textContent = (i+1) + ". " + data[entitiesOrInterests][i].name; //Add Image/Branding name.appendChild(insertInfegyLightbulbLogo("logo")); //Add Name box.appendChild(name); return box; } //This bit of code builds each entity box //TODO - Clean it up and abstract it out some function buildEntityBox(data, i) { // Create a new box div const box = document.createElement('div'); box.classList.add('entity_box'); box.setAttribute("onclick",'loadEntityPage("'+data[entitiesOrInterests][i].name+'")'); createEntityNameSummary(data, box, i); const flex_table = document.createElement("div"); flex_table.classList.add("flex-table"); //Post Volume Label const postVolumeCell = document.createElement("div"); postVolumeCell.className = 'most_trusted_cell'; postVolumeCell.id = 'volume' postVolumeCell.innerHTML ="
Trust
" + "

" + numberWithCommas(Math.round(data[entitiesOrInterests][i].positive_trust)) +"

"; //Post Volume Label const posSentimentCell = document.createElement("div"); posSentimentCell.className = 'most_trusted_cell'; posSentimentCell.id = 'posSentiment' posSentimentCell.innerHTML = "
Positive
"+ "

"+ data[entitiesOrInterests][i].positive_sentiment +"%

"; //Post Volume Label const negSentimentCell = document.createElement("div"); negSentimentCell.className = 'most_trusted_cell'; negSentimentCell.id = 'negSentiment' negSentimentCell.innerHTML = "
Negative
"+ "

"+ data[entitiesOrInterests][i].negative_sentiment +"%

"; flex_table.appendChild(posSentimentCell); flex_table.appendChild(postVolumeCell); flex_table.appendChild(negSentimentCell); box.appendChild(flex_table); //Add Entity Summary const summary = document.createElement('p'); summary.append(data[entitiesOrInterests][i].summary); box.appendChild(summary); return box; } //This function adds the navigation buttons to navigate in between trends, linguistics, posts, and geography function addEntityNavButtons() { var listOfButtonsToAdd = ['Trends', 'Linguistics', 'Geography']; var buttonContainer = document.createElement('div'); buttonContainer.classList.add("button-row"); buttonContainer.classList.add("navButtons"); for (let i = 0; i < listOfButtonsToAdd.length; i++) { var tempButton = document.createElement("button"); tempButton.classList.add("view-button"); tempButton.id = "button" + (i+1); tempButton.textContent=listOfButtonsToAdd[i]; buttonContainer.append(tempButton); } return buttonContainer; } //This function adds the timeframe buttons to navigate in between the different time frames in the dashboard function addTimeFrameButtons() { var listOfButtonsToAdd = ['1 year ago', '1 month ago', '1 week ago']; var buttonContainer = document.createElement('div'); buttonContainer.classList.add("button-row"); buttonContainer.classList.add("timeButtons"); for (let i = 0; i < listOfButtonsToAdd.length; i++) { var tempButton = document.createElement("button"); tempButton.classList.add("time-button"); tempButton.id = "button" + (i+1); tempButton.textContent=listOfButtonsToAdd[i]; buttonContainer.append(tempButton); } return buttonContainer; } //This function adds the timeframe buttons to navigate in between the different time frames in the dashboard function addDataButtons(listOfButtonsToAdd) { var buttonContainer = document.createElement('div'); buttonContainer.classList.add("button-row"); buttonContainer.classList.add("dataButtons"); for (let i = 0; i < listOfButtonsToAdd.length; i++) { var tempButton = document.createElement("button"); tempButton.classList.add("data-button"); tempButton.id = "button" + (i+1); tempButton.textContent=listOfButtonsToAdd[i]; buttonContainer.append(tempButton); } return buttonContainer; } //This function will build the trends html skeleton of the entity page function buildTrendsTab() { const trendsTab = document.createElement('div'); trendsTab.classList.add('view'); trendsTab.id = 'view1'; const trendsParagraph = document.createElement('p'); trendsParagraph.textContent = "The Trends tab allows you to view how your research topic has trended over the selected timeframe. This tab is best for understanding volume fluctuations, percent change, trend events, and more."; trendsTab.append(trendsParagraph); trendsTab.append(addTimeFrameButtons()); trendsTab.append(addDataButtons(['Universe', 'Sentiment', 'Emotions'])); const chartDiv = document.createElement('div'); chartDiv.classList.add("trendsChartContainer"); const trendsChart = document.createElement('canvas'); trendsChart.id = 'ct-chart-trends'; chartDiv.append(trendsChart); trendsTab.append(chartDiv); return trendsTab; } function buildInfoBoxes(idType) { //Overall Gradient Information Row const informationContainer = document.createElement('div'); informationContainer.classList.add('information-row'); //Gradient Box const colorGradientBox = document.createElement('div'); colorGradientBox.classList.add('info-box'); //Gradient Description const colorGradientDescription = document.createElement('p'); colorGradientDescription.classList.add('color-gradient-description'); colorGradientDescription.id = idType + "-info-box" if (idType == 'geography') { colorGradientDescription.textContent = "Universe"; } else { colorGradientDescription.textContent = "Sentiment"; } colorGradientBox.appendChild(colorGradientDescription); //Actual Gradient const colorGradient = document.createElement('div'); colorGradient.id = idType + "-color-gradient" if (idType == 'linguistics') { colorGradient.classList.add("color-gradient-sentiment"); } else { colorGradient.classList.add("color-gradient-universe"); } colorGradientBox.appendChild(colorGradient); informationContainer.appendChild(colorGradientBox); return informationContainer } //This function will build the linguistics html skeleton of the entity page //abstract out the different gradients and trendlines function buildLinguisticsTab() { const linguisticsTab = document.createElement('div'); linguisticsTab.classList.add('view'); linguisticsTab.id = 'view2'; const linguisticsParagraph = document.createElement('p'); linguisticsParagraph.textContent = "The Linguistics tab shows the actual words and hashtags present within posts and documents. We also show mentions here showing which accounts frequently appear. They are colored by sentiment, showing how positive or negative the overall conversation is around the topics."; linguisticsTab.append(linguisticsParagraph); linguisticsTab.append(addTimeFrameButtons()); linguisticsTab.append(addDataButtons(['Topics', 'Hashtags', 'Mentions'])); const linguisticsWordCloud = document.createElement("div"); linguisticsWordCloud.classList.add('wordCloudContainer'); linguisticsWordCloud.id = "wordcloud"; linguisticsTab.appendChild(linguisticsWordCloud); const informationContainer = buildInfoBoxes("linguistics") linguisticsTab.append(informationContainer); return linguisticsTab } //This function will build the geography html skeleton of the entity page function buildGeographyTab() { const geographyTab = document.createElement('div'); geographyTab.classList.add('view'); geographyTab.id = 'view3'; const geographyParagraph = document.createElement('p'); geographyParagraph.textContent = "Using a normalized approach, Infegy Starscape provides an accurate read on where interest in your research topic lies across the globe. Here, we rank countries by overall volume, sentiment, and trust score. With trust score, we are looking at the countries that have the highest number of positive documents containing trust."; geographyTab.append(geographyParagraph); geographyTab.append(addTimeFrameButtons()); geographyTab.append(addDataButtons(['Universe', 'Sentiment', 'Trust Score'])); const mapContainer = document.createElement('div'); mapContainer.id = 'map' geographyTab.append(mapContainer); const informationContainer = buildInfoBoxes("geography") geographyTab.append(informationContainer); return geographyTab } function getColor(country, countryCode) { var color; if (countryCode == undefined) { color = "#ffffff" } else { try { color = country[countryCode]['color'] } catch { color = "#ffffff" } } return color } function updateMap(id, map, data) { map.off(); map.remove(); map = drawMap(id, data); return map; } function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } function drawMap(id, data) { var container = L.DomUtil.get("map"); if (container != null) { container._leaflet_id = null; } document.getElementById(id).innerHTML = ""; var map = L.map(id, { center: [23, 0], crs: L.CRS.EPSG3857, zoom: 2, maxZoom: 4, zoomControl: false, preferCanvas: false, scrollWheelZoom: false, dragging: false, attributionControl: false, } ); function style(feature) { return { fillColor: getColor(data, feature.properties.iso2), weight: 2, opacity: .5, color: 'lightgrey', fillOpacity: 0.7 }; } function highlightFeature(e) { var layer = e.target; layer.setStyle({ weight: 5, color: '#666', dashArray: '', fillOpacity: 0.7 }); layer.bringToFront(); info.update(layer.feature.properties); } function resetHighlight(e) { geojson.resetStyle(e.target); info.update(); } function onEachFeature(feature, layer) { layer.on({ mouseover: highlightFeature, mouseout: resetHighlight, }); } var info = L.control(); info.onAdd = function (map) { this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info" this.update(); return this._div; }; // method that we will use to update the control based on feature properties passed info.update = function (props) { if (currentDataView == 'universe') { this._div.innerHTML = '

Universe by Country

' + (props ? '' + props.ADMIN + '
' + numberWithCommas(Math.round(data[props.iso2].data)) + ' posts' : 'Hover over a country'); } else if (currentDataView == 'sentiment') { this._div.innerHTML = '

Sentiment by Country

' + (props ? '' + props.ADMIN + '
' + Math.round(data[props.iso2].data*100) + '% positivity' : 'Hover over a country'); } else if (currentDataView == 'trust score') { this._div.innerHTML = '

Trust Score by Country

' + (props ? '' + props.ADMIN + '
' + Math.round(data[props.iso2].data*100)/100 : 'Hover over a country'); } }; info.addTo(map); var geojson = L.geoJson(siteData['countries'], {style: style, onEachFeature: onEachFeature}).addTo(map); return map; } //Thus function constructs the map for the trends chart. function buildChartData(entityIndex, currentView, timeframe, dataView) { let dataSeries = siteData[entitiesOrInterests][entityIndex][currentView][timeframe][dataView] let dates = dataSeries['dates'] let dataForChart = [] var keys = Object.keys(dataSeries); for (let i = 0; i < keys.length; i++) { if (keys[i] != 'dates') { dataForChart.push(dataSeries[keys[i]]); } } var data = { labels:dates, series: dataForChart, }; return data; } //This function draws the linguistics word clouds. It uses d3 as a dependency. function drawWordCloud(myWords) { myWordsCached = myWords; document.getElementById("wordcloud").innerHTML = ""; // set the dimensions and margins of the graph var margin = {top: 10, right: 10, bottom: 10, left: 10}; var width = document.getElementById('wordcloud').clientWidth - margin.left - margin.right; var height = document.getElementById('wordcloud').clientHeight - margin.top - margin.bottom; var fontscale = d3.scalePow() .exponent(.25) .domain([0, 100]) .range([0, 20]); // append the svg object to the body of the page var svg = d3.select("#wordcloud").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Constructs a new cloud layout instance. It run an algorithm to find the position of words that suits your requirements // Wordcloud features that are different from one word to the other must be here var layout = d3.layout.cloud() .size([width, height]) .words(myWords.map(function(d) { return {text: d.word, size:d.size, color:d.color, timeline:d.timeline}; })) .padding(15) //space between words .rotate(function() { return ~~(Math.random() * 2) * 0; }) .fontSize(function(d) { return fontscale(d.size); }) // font size of words .on("end", draw); layout.start(); // This function takes the output of 'layout' above and draw the words // Wordcloud features that are THE SAME from one word to the other can be here function draw(words) { svg .append("g") .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") .selectAll("text") .data(words) .enter().append("text") .style("font-size", function(d) { return d.size; }) .style("fill", function(d) { return d.color;}) .attr("text-anchor", "middle") .style("font-family", "Roboto") .attr("transform", function(d) { return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; }) .text(function(d) { return d.text; }) .on("mouseover", function (d) { // Generate the chart using Chartist var seriesData = { series: [d.timeline] }; //topicChart.update(seriesData); }); } var seriesData = { series: [myWords[0].timeline] }; } //This function handles the resizing for the linguistics word cloud window.addEventListener('resize', function(event) { if ((currentView == 'linguistics') && (document.getElementById("wordcloud").innerHTML != null)) { drawWordCloud(myWordsCached); } }, true); function titleCase(str) { return str.toLowerCase().replace(/\b\w/g, s => s.toUpperCase()); } //This function loads each Entity Page when the user clicks on an entity from the main page. function loadEntityPage(entityName) { clearCards(); var div = document.getElementById("boxContainer") //Build Return Home Button var buttonCenter = document.createElement("div"); buttonCenter.classList.add("text-center"); var returnHomeButton = document.createElement('button'); returnHomeButton.classList.add("return-button"); returnHomeButton.textContent="Return To List"; returnHomeButton.setAttribute("onclick",'populateSubPage("' + entitiesOrInterests + '")'); buttonCenter.appendChild(returnHomeButton); div.appendChild(buttonCenter); //Get Index key so you can hit the data appropriately var entityIndex = siteData['key'][entitiesOrInterests][entityName]; //Build Main Entity Page var entityPage = document.createElement('div'); entityPage.classList.add("entityPage"); //Build Title (H2) const title = document.createElement('h2'); title.textContent = (entityIndex + 1) + ". " + entityName; title.classList.add('entityTitle'); //Insert Infegy Logo title.appendChild(insertInfegyLightbulbLogo("logo")); entityPage.appendChild(title); //Build positive trust const positive_trust = document.createElement('h4'); positive_trust.textContent = "Positive Trust Score: " + numberWithCommas(Math.round(siteData[entitiesOrInterests][entityIndex].positive_trust)) + " posts"; entityPage.appendChild(positive_trust); //Build Summary const summary = document.createElement('p'); summary.textContent = siteData[entitiesOrInterests][entityIndex].summary; summary.classList.add('entitySummary'); entityPage.append(summary); currentEntity = entityName; currentView = "trends"; currentTimeFrame = "1 year ago"; currentDataView = "universe"; //Build analysis tabs for each entity entityPage.append(addEntityNavButtons()); entityPage.appendChild(buildTrendsTab()); entityPage.appendChild(buildLinguisticsTab()); entityPage.appendChild(buildGeographyTab()); //Build Return Home Button //var buttonCenter = document.createElement("div"); //buttonCenter.classList.add("text-center"); //var returnHomeButton = document.createElement('button'); //returnHomeButton.classList.add("return-button"); //returnHomeButton.textContent="Download this data"; //returnHomeButton.setAttribute("onclick",'downloadData()'); //buttonCenter.appendChild(returnHomeButton); //entityPage.appendChild(buttonCenter); div.append(entityPage); handleViewButtonSelection(); handleTimeButtonSelection(); handleDataButtonSelection(); //Build first graph (trends default view) var data = buildChartData(entityIndex, 'trends', '1 year ago', 'universe'); var ctx = document.getElementById('ct-chart-trends').getContext('2d'); trendsChart = buildTrendsChart(ctx, data, 'universe'); var elementToScrollTo = document.getElementById('boxContainer');; if (elementToScrollTo) { // Scroll to the top of the element elementToScrollTo.scrollIntoView(); } } //this function loads the initial page (entity card tiles) function loadInitialPage(url) { fetch(url).then(response => {return response.json();}).then(data => { siteData = data; populateSubPage("entities"); //load updated page thing var last_updated = document.getElementById("last_updated") // last_updated.textContent = "Updated on: " + siteData['time_updated']; }); } //This function loads each of the entity cards in the main view function populateSubPage(textLabel) { clearCards(); entitiesOrInterests = textLabel; var div = document.getElementById("boxContainer") const container = document.createElement('div'); container.classList.add('most_trusted_brands_container'); // Loop through the data array and create a box for each item for (let i = 0; i < siteData[entitiesOrInterests].length; i++) { //Add each entity box to the container container.appendChild(buildEntityBox(siteData, i)); document.getElementById("boxContainer").appendChild(container); } var elementToScrollTo = document.querySelector('.most_trusted_brands'); if (elementToScrollTo) { // Scroll to the top of the element elementToScrollTo.scrollIntoView(); } } //This function deletes all the entity cards function clearCards(){ // Get a reference to the div element var div = document.getElementById("boxContainer"); // Clear the contents by setting the innerHTML property to an empty string div.innerHTML = ""; } //loadInitialPage("siteData.json") loadInitialPage("https://1716283.fs1.hubspotusercontent-na1.net/hubfs/1716283/Top_Brands_2024_Refresh/siteData.json") function jsonToCsv(items, currentEntity, currentView, currentTimeFrame, currentDataView) { let mainArray = [] if (currentView == 'trends') { const header = Object.keys(items); //initialize first list let headerArray = [] for (let i = 0; i < header.length; i++){ headerArray.push(header[i]); } mainArray.push(headerArray); //Loop through each row of JSON data for (let i = 0; i < items[header[0]].length; i++) { var rowArray = [] for (let j = 0; j < header.length; j++) { rowArray.push(items[header[j]][i]); } mainArray.push(rowArray); } } else if (currentView == 'linguistics') { mainArray = items; } else if (currentView == 'geography') { const countries = Object.keys(items); let headerArray = ['name', 'data', 'timeline']; mainArray.push(headerArray); for (let i = 0; i < countries.length; i++) { var rowArray = [] rowArray.push(CountryLookup[countries[i]]); rowArray.push(items[countries[i]]['data']); rowArray.push(items[countries[i]]['timeline']); mainArray.push(rowArray); } } var csv = Papa.unparse(mainArray); // Start file download. download(currentEntity + " - " + currentView + " - " + currentTimeFrame + " - " + currentDataView + ".csv", csv); return "hello"; } function download(filename, text) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } function downloadData() { jsonToCsv(siteData[entitiesOrInterests][siteData['key'][entitiesOrInterests][currentEntity]][currentView][currentTimeFrame][currentDataView], currentEntity, currentView, currentTimeFrame, currentDataView); } var CountryLookup = { "AF": "Afghanistan", "AX": "Aland Islands", "AL": "Albania", "DZ": "Algeria", "AS": "American Samoa", "AD": "Andorra", "AO": "Angola", "AI": "Anguilla", "AQ": "Antarctica", "AG": "Antigua And Barbuda", "AR": "Argentina", "AM": "Armenia", "AW": "Aruba", "AU": "Australia", "AT": "Austria", "AZ": "Azerbaijan", "BS": "Bahamas", "BH": "Bahrain", "BD": "Bangladesh", "BB": "Barbados", "BY": "Belarus", "BE": "Belgium", "BZ": "Belize", "BJ": "Benin", "BM": "Bermuda", "BT": "Bhutan", "BO": "Bolivia", "BA": "Bosnia And Herzegovina", "BW": "Botswana", "BV": "Bouvet Island", "BR": "Brazil", "IO": "British Indian Ocean Territory", "BN": "Brunei Darussalam", "BG": "Bulgaria", "BF": "Burkina Faso", "BI": "Burundi", "KH": "Cambodia", "CM": "Cameroon", "CA": "Canada", "CV": "Cape Verde", "KY": "Cayman Islands", "CF": "Central African Republic", "TD": "Chad", "CL": "Chile", "CN": "China", "CX": "Christmas Island", "CC": "Cocos (Keeling) Islands", "CO": "Colombia", "KM": "Comoros", "CG": "Congo", "CD": "Congo, Democratic Republic", "CK": "Cook Islands", "CR": "Costa Rica", "CI": "Cote D\"Ivoire", "HR": "Croatia", "CU": "Cuba", "CY": "Cyprus", "CZ": "Czech Republic", "DK": "Denmark", "DJ": "Djibouti", "DM": "Dominica", "DO": "Dominican Republic", "EC": "Ecuador", "EG": "Egypt", "SV": "El Salvador", "GQ": "Equatorial Guinea", "ER": "Eritrea", "EE": "Estonia", "ET": "Ethiopia", "FK": "Falkland Islands (Malvinas)", "FO": "Faroe Islands", "FJ": "Fiji", "FI": "Finland", "FR": "France", "GF": "French Guiana", "PF": "French Polynesia", "TF": "French Southern Territories", "GA": "Gabon", "GM": "Gambia", "GE": "Georgia", "DE": "Germany", "GH": "Ghana", "GI": "Gibraltar", "GR": "Greece", "GL": "Greenland", "GD": "Grenada", "GP": "Guadeloupe", "GU": "Guam", "GT": "Guatemala", "GG": "Guernsey", "GN": "Guinea", "GW": "Guinea-Bissau", "GY": "Guyana", "HT": "Haiti", "HM": "Heard Island & Mcdonald Islands", "VA": "Holy See (Vatican City State)", "HN": "Honduras", "HK": "Hong Kong", "HU": "Hungary", "IS": "Iceland", "IN": "India", "ID": "Indonesia", "IR": "Iran, Islamic Republic Of", "IQ": "Iraq", "IE": "Ireland", "IM": "Isle Of Man", "IL": "Israel", "IT": "Italy", "JM": "Jamaica", "JP": "Japan", "JE": "Jersey", "JO": "Jordan", "KZ": "Kazakhstan", "KE": "Kenya", "KI": "Kiribati", "KR": "Korea", "KP": "North Korea", "KW": "Kuwait", "KG": "Kyrgyzstan", "LA": "Lao People\"s Democratic Republic", "LV": "Latvia", "LB": "Lebanon", "LS": "Lesotho", "LR": "Liberia", "LY": "Libyan Arab Jamahiriya", "LI": "Liechtenstein", "LT": "Lithuania", "LU": "Luxembourg", "MO": "Macao", "MK": "Macedonia", "MG": "Madagascar", "MW": "Malawi", "MY": "Malaysia", "MV": "Maldives", "ML": "Mali", "MT": "Malta", "MH": "Marshall Islands", "MQ": "Martinique", "MR": "Mauritania", "MU": "Mauritius", "YT": "Mayotte", "MX": "Mexico", "FM": "Micronesia, Federated States Of", "MD": "Moldova", "MC": "Monaco", "MN": "Mongolia", "ME": "Montenegro", "MS": "Montserrat", "MA": "Morocco", "MZ": "Mozambique", "MM": "Myanmar", "NA": "Namibia", "NR": "Nauru", "NP": "Nepal", "NL": "Netherlands", "AN": "Netherlands Antilles", "NC": "New Caledonia", "NZ": "New Zealand", "NI": "Nicaragua", "NE": "Niger", "NG": "Nigeria", "NU": "Niue", "NF": "Norfolk Island", "MP": "Northern Mariana Islands", "NO": "Norway", "OM": "Oman", "PK": "Pakistan", "PW": "Palau", "PS": "Palestinian Territory, Occupied", "PA": "Panama", "PG": "Papua New Guinea", "PY": "Paraguay", "PE": "Peru", "PH": "Philippines", "PN": "Pitcairn", "PL": "Poland", "PT": "Portugal", "PR": "Puerto Rico", "QA": "Qatar", "RE": "Reunion", "RO": "Romania", "RU": "Russian Federation", "RW": "Rwanda", "BL": "Saint Barthelemy", "SH": "Saint Helena", "KN": "Saint Kitts And Nevis", "LC": "Saint Lucia", "MF": "Saint Martin", "PM": "Saint Pierre And Miquelon", "VC": "Saint Vincent And Grenadines", "WS": "Samoa", "SM": "San Marino", "ST": "Sao Tome And Principe", "SA": "Saudi Arabia", "SN": "Senegal", "RS": "Serbia", "SC": "Seychelles", "SL": "Sierra Leone", "SG": "Singapore", "SK": "Slovakia", "SI": "Slovenia", "SB": "Solomon Islands", "SO": "Somalia", "ZA": "South Africa", "GS": "South Georgia And Sandwich Isl.", "ES": "Spain", "LK": "Sri Lanka", "SD": "Sudan", "SR": "Suriname", "SJ": "Svalbard And Jan Mayen", "SZ": "Swaziland", "SE": "Sweden", "CH": "Switzerland", "SY": "Syrian Arab Republic", "TW": "Taiwan", "TJ": "Tajikistan", "TZ": "Tanzania", "TH": "Thailand", "TL": "Timor-Leste", "TG": "Togo", "TK": "Tokelau", "TO": "Tonga", "TT": "Trinidad And Tobago", "TN": "Tunisia", "TR": "Turkey", "TM": "Turkmenistan", "TC": "Turks And Caicos Islands", "TV": "Tuvalu", "UG": "Uganda", "UA": "Ukraine", "AE": "United Arab Emirates", "GB": "United Kingdom", "US": "United States", "UM": "United States Outlying Islands", "UY": "Uruguay", "UZ": "Uzbekistan", "VU": "Vanuatu", "VE": "Venezuela", "VN": "Vietnam", "VG": "Virgin Islands, British", "VI": "Virgin Islands, U.S.", "WF": "Wallis And Futuna", "EH": "Western Sahara", "YE": "Yemen", "ZM": "Zambia", "ZW": "Zimbabwe" }