123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /**
- * QUERY SECTION
- *
- * */
- // SPARQL Query text -- 'prefixes' and 'thisUrlParams' defined in people.js;
- let queryNetwork = prefixes + " SELECT COUNT(?event1) AS ?count1 COUNT(?event2) AS ?count2 ?uri2 SAMPLE(?label2) AS ?text \
- WHERE { \
- {?event1 rdf:type crm:EL1_Exchange_Letters . \
- ?event_to rdfs:subClassOf ?event1; \
- rdf:type crm:EL2_Send_Letter ; \
- crm:P01_has_domain ?pc_to . \
- ?pc_to crm:P02_has_range ?uri . \
- ?uri rdfs:label ?label . \
- ?event_from rdfs:subClassOf ?event1; \
- rdf:type crm:EL3_Receive_Letter; \
- crm:P01_has_domain ?pc_from . \
- ?pc_from crm:P02_has_range ?uri2 . \
- ?uri2 rdfs:label ?label2 . \
- FILTER (?uri = <" + thisUrlParams.link + ">) \
- } UNION { \
- ?event2 rdf:type crm:EL1_Exchange_Letters . \
- ?event_to rdfs:subClassOf ?event2; \
- rdf:type crm:EL3_Receive_Letter ; \
- crm:P01_has_domain ?pc_from . \
- ?pc_from crm:P02_has_range ?uri . \
- ?uri rdfs:label ?label . \
- ?event_from rdfs:subClassOf ?event2; \
- rdf:type crm:EL2_Send_Letter; \
- crm:P01_has_domain ?pc_to . \
- ?pc_to crm:P02_has_range ?uri2 . \
- ?uri2 rdfs:label ?label2 . \
- FILTER (?uri = <" + thisUrlParams.link + ">) \
- } \
- }"
- // 'prepareQueryURL' defined in people.js
- let queryNet = prepareQueryURL(queryNetwork);
- // do the query, call data processor on successful output
- $.ajax({
- url: queryNet,
- dataType: "json",
- success: (data) => handle_word_network(data)
- });
- // queryLetters defined in people.js
- console.log(queryLetters);
- /**
- * COMPONENT CREATION SECTION
- *
- * */
- // Master function, takes data output from the query and creates the HTML for the Word Cloud component of the page
- function handle_word_network(json){
- // Pre-process data
- let words = processQuery(json);
- // Create page elements
- doListPersonNetwork(words);
- doWordCloud(words);
- }
- // Return structured object from raw query data for further processing
- function processQuery(json) {
-
- const tempArray = [];
-
- $.each(
- json['results']['bindings'],
- (index, value) => {
- let text = value['text']['value'];
- let link = value['uri2']['value'];
- let sent = parseInt(value['count1']['value']);
- let received = parseInt(value['count2']['value']);
- let count = sent + received;
- tempArray.push({'text': text, 'sent': sent, 'received': received, 'count': count, 'hlink': link});
- }
- );
- tempArray.sort((a, b) => b.count - a.count);
- return tempArray;
- }
- // Create formatted list of people in the network
- function doListPersonNetwork(words){
- let ArrayNames = "";
- words.forEach(element => {
- filteredText = element['text'].replace('"', '').replace("'", '');
- ArrayNames +=
- "<div class='item-place-person'>"+
- "<div class='item-place-person-label' id='list-" + filteredText + "'>" +
- element['text'] +
- "<br /><span class='num_occ'>[Lettere inviate: " + element['sent'] + "]</span>" +
- "<br /><span class='num_occ'>[Lettere ricevute: " + element['received'] + "]</span>" +
- "<br /><span id='tot-"+filteredText+"' class='num_occ'>[Totale corrispondenza: " + element['count'] + "]</span>" +
- "</div>" +
- "<div class='item-place-person-action'>" +
- "<div class='persona' id='" + element['hlink'] +"'>" +
- "<i class='fa fa-user' style='cursor:pointer'></i>" +
- "</div>" +
- "</div>" +
- "</div>";
- });
- document.getElementById("list_person_network").innerHTML = ArrayNames;
- addEventsToNameList(words);
- }
- function addEventsToNameList(words){
- let counter = 0
- for(let word of words){
- if(counter>0) break;
- let listElem = document.getElementById('tot-' + word.text.replace('"', '').replace("'", ''));
- if(listElem!=null){
- listElem.addEventListener("click", filterLetters);
- listElem.addEventListener("mouseover", highlightWord);
- listElem.addEventListener("mouseout", unHighlightWord);
- }
- counter++;
- }
- }
- function filterLetters(e){
- try{
- let preText = e.target.parentNode.textContent;
- console.log('text content', preText);
- let name = preText.split("[")[0];
- console.log('name', name);
- // responseLet defined in people.js
- responseLet.then(data => {
-
- let lettersJson = data.results.bindings;
- lettersJson = lettersJson.filter(letter => letter.otherPerson.value==name);
- console.log(lettersJson);
- });
- } catch{
- console.log("Couldn't get the name");
- }
- }
- // Create the word cloud
- function doWordCloud(words){
-
- // Clear word cloud div
- $('#myWordCloud').empty();
- // OVERALL GRAPHIC SETTINGS for the cloud container -- id, dimensions, position
- let width = 0.5*window.outerWidth;
- let height = 0.6*width;
-
- // append the svg object to the body of the page
- let svg = d3.select("#myWordCloud")
- .append("svg")
- .attr("id", "wordcloudNetwork")
- .attr("preserveAspectRatio", "xMinYMin meet")
- .attr("viewBox", "0 0 " + width + " " + height)
- .classed("svg-content", true)
- .attr("width", width)
- .attr("height", height)
- .attr("style", "border:1px solid black")
- // In case of empty cloud, draw special page and exit
- if (words.length == 0){
- drawEmptyWordCloud();
- return;
- }
-
- // THE ACTUAL CLOUD
- svg = document.getElementById('wordcloudNetwork');
- console.log(svg);
- let zoom = window.devicePixelRatio;
- console.log('zoom', zoom);
- wcParameters = {
- svgWidth: svg.getBoundingClientRect().width,
- svgHeight: svg.getBoundingClientRect().height,
- maxFontSize: 30/((1+zoom)/2),
- minFontSize: 10/((1+zoom)/2)
- }
- let svgWords = hackWords(words, wcParameters);
- svg.innerHTML = svgWords;
- let wordCloudText = createWordCloud(words, wcParameters);
- svg.innerHTML = wordCloudText;
- addEventsToWordCloud(words);
- }
- // Helper function -- draw special empty word cloud if there are no occurrences
- function drawEmptyWordCloud(){
- let wordIcon = "<div id='users_icon' class='no_info_icon'> \
- <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'> \
- <!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d='M319.9 320c57.41 0 103.1-46.56 103.1-104c0-57.44-46.54-104-103.1-104c-57.41 0-103.1 46.56-103.1 104C215.9 273.4 262.5 320 319.9 320zM369.9 352H270.1C191.6 352 128 411.7 128 485.3C128 500.1 140.7 512 156.4 512h327.2C499.3 512 512 500.1 512 485.3C512 411.7 448.4 352 369.9 352zM512 160c44.18 0 80-35.82 80-80S556.2 0 512 0c-44.18 0-80 35.82-80 80S467.8 160 512 160zM183.9 216c0-5.449 .9824-10.63 1.609-15.91C174.6 194.1 162.6 192 149.9 192H88.08C39.44 192 0 233.8 0 285.3C0 295.6 7.887 304 17.62 304h199.5C196.7 280.2 183.9 249.7 183.9 216zM128 160c44.18 0 80-35.82 80-80S172.2 0 128 0C83.82 0 48 35.82 48 80S83.82 160 128 160zM551.9 192h-61.84c-12.8 0-24.88 3.037-35.86 8.24C454.8 205.5 455.8 210.6 455.8 216c0 33.71-12.78 64.21-33.16 88h199.7C632.1 304 640 295.6 640 285.3C640 233.8 600.6 192 551.9 192z'/> \
- </svg> \
- <p>Nessuna persona trovata</p> \
- </div>";
- $("#wordcloudNetwork").css("display", "none");
- $("#references_network").css("display", "none");
- document.getElementById("myWordCloud").innerHTML = wordIcon;
- }
- /*****************************
- * Customized word cloud code *
- *****************************/
- function hackWords(words, parameters){
- let weights = words.map(word => word.count);
- let minWeight = Math.min(...weights);
- let maxFontSize = parameters.maxFontSize;
- let minFontSize = parameters.minFontSize;
- console.log('weights', weights);
- console.log('maxFontSize', maxFontSize);
- console.log('minFontSize',minFontSize);
- let stringOfWords = "";
- for(let ind=0; ind<words.length; ind++){
- let word = words[ind];
- word.fontSize = getFontSize(words[ind].count, minWeight, maxFontSize, minFontSize);
- stringOfWords = stringOfWords+
- '<text x="100" y ="' + (maxFontSize + maxFontSize*ind).toString() + '" + font-family="Verdana" font-size="'+(word.fontSize)+'" id="word' + ind + '">'+words[ind].text+'</text>\n';
- }
- return stringOfWords;
- }
- // Takes a list of words, returns the innerHTML for a Word Cloud as a string containing multiple <g> svg elements
- function createWordCloud(words, parameters){
- let actualUsefulWidth = parameters.svgWidth;
- let actualUsefulHeight = parameters.svgHeight;
- console.log('Actual SVG dimensions', actualUsefulWidth, actualUsefulHeight);
- maxFontSize = parameters.maxFontSize;
- minFontSize = parameters.minFontSize;
- const rectObjs = []
- let allBooms = 0
- let attempts = 0;
- let outOfBorder = 0;
- for(let ind=0;ind<words.length;ind++){
- //for(let ind=0;ind<3;ind++){
- // Control vars
- if(allBooms>=20*(ind+1)) break;
- attempts++;
- let boom = false;
- // word + bounding box parameters definition
- let word = words[ind];
- let id0 = "word"+ind;
- let wordBB = document.getElementById(id0).getBoundingClientRect();
- let fontSize = word.fontSize;
- let width = wordBB.width;
- let height = wordBB.height;
- let multiplier = 0.1 + 0.4*Math.max((maxFontSize-fontSize)/(maxFontSize-minFontSize), allBooms/(20*(ind+1)));
- let xR = Math.floor(actualUsefulWidth/2-width/2 + randomRange(-multiplier*actualUsefulWidth, multiplier*actualUsefulWidth));
- let yR = Math.floor(actualUsefulHeight/2 + randomRange(-multiplier*actualUsefulHeight, multiplier*actualUsefulHeight));
- //console.log('x', 'y', xR, yR)
- let angle;
- if(word.received/word.sent>3) angle = -3;
- else if(word.received/word.sent<0.3) angle = 3;
- let text = word.text;
- //console.log('Rect:', width, height, xR, yR, angle, text);
- //
- let newRect = new Rect(width, height, xR, yR, angle, text, fontSize);
- boom = checkBorder(newRect, 0, actualUsefulWidth, 0, actualUsefulHeight)
- if(boom){
- outOfBorder++;
- if(outOfBorder<30){
- ind--;
- continue;
- } else{
- boom = false;
- }
- }
- for(let rect of rectObjs){
- boom = checkColl(newRect, rect);
- if(boom) break;
- }
- if(boom){
- allBooms++;
- ind--;
- continue;
- }
- allBooms = 0;
- rectObjs.push(newRect);
- }
- console.log('Attempted:', attempts);
- console.log('Placed:', rectObjs.length);
- console.log('booms!', allBooms);
- const rectTexts = [];
- rectObjs.forEach(rect => rectTexts.push(rect.printCoords(false, maxFontSize, minFontSize)));
- let rects = rectTexts.join('\n');
- return rects;
- }
- function getFontSize(weight, minWeight, maxFontSize, minFontSize){
- let r1 = weight/10*minWeight - 1/10; // between 0 and a big num
- let res = minFontSize + (maxFontSize-minFontSize)*r1/Math.sqrt(1+r1**2);
- return res;
- }
- function randomRange(a, b=0){
- return (a-b)*Math.random()+b;
- }
- function randomInt(a){
- return Math.floor(a*Math.random());
- }
- function randomRangeInt(a, b=0){
- let ap = Math.floor(a);
- let bp = Math.floor(b);
- return Math.floor((ap-bp)*Math.random())+bp;
- }
- // Check border collision
- function checkBorder(rect, minX, maxX, minY, maxY){
- if(rect.minX<minX) return true;
- if(rect.maxX>maxX) return true;
- if(rect.minY<minY) return true;
- if(rect.maxY>maxY) return true;
- return false;
- }
- function addEventsToWordCloud(words){
- for(let word of words){
- let wcElem = document.getElementById('word-' + word.text.replace('"', '').replace("'", ''));
- if(wcElem!=null){
- wcElem.addEventListener("click", focusPersonInList);
- wcElem.addEventListener("mouseover", highlightWord);
- wcElem.addEventListener("mouseout", unHighlightWord);
- }
- }
- }
- function focusPersonInList(e){
- let targetId = e.target.id;
- console.log(targetId);
- let listElem = document.getElementById(targetId.replace('word-', 'list-'));
- listElem.scrollIntoView({behavior: "smooth", block: "center"});
- }
- function highlightWord(e){
- e.target.style['text-decoration'] = "underline";
- }
- function unHighlightWord(e){
- e.target.style['text-decoration'] = "";
- }
|