Преглед на файлове

Implementar visualização de todos os alunos

Implementar bloco de seleção de area no mapa de calor

Implementar informações do ponto no mapa de calor
Lucas de Souza преди 5 години
родител
ревизия
54b57b2741

+ 2 - 1
.gitignore

@@ -35,4 +35,5 @@ Thumbs.db
 !.vscode/launch.json
 !.vscode/extensions.json
 
-./cursos/
+cursos/
+temp/

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/line_heatmap.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/line_heatmap.js.map


+ 3 - 1
index.html

@@ -7,6 +7,8 @@
   <link rel="stylesheet" href="dist/style.css">
   <style>
     #line-heatmap-canvas { width:60%; height:60%; position:absolute; }
+    #line-heatmap-view { width:60%; height:60%; position:absolute; }
+    #line-heatmap-tooltip { position:absolute; left:0; top:0; background:rgba(0,0,0,.8); color:white; font-size:14px; padding:5px; line-height:18px; display:none;}
   </style>
   <title>Test</title>
 </head>
@@ -17,7 +19,7 @@
   </div>
   <script src="dist/line_heatmap.js"></script>
   <script>
-    line_heatmap.Container.init('hea',"100,200,1,0\n100,200,1,0\n100,200,1,0\n100,200,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0");
+    line_heatmap.Container.init('hea',"100,200,1,0\n100,200,1,0\n100,200,1,0\n100,200,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0\n250,350,1,0", true, {radius:100});
   </script>
 </body>
 </html>

+ 2 - 2
ivprog_contexto/css/ivprog-visual-1.0.css

@@ -16,8 +16,8 @@ body {
 
 .ivprog_visual_panel {
 	height: 96%;
-	overflow: auto;
-	overflow-x: auto;
+	/*overflow: auto;
+	overflow-x: auto;*/
 }
 
 .ivprog_textual_code {

+ 2 - 2
ivprog_menu/css/ivprog-visual-1.0 (cópia).css

@@ -16,8 +16,8 @@ body {
 
 .ivprog_visual_panel {
 	height: 96%;
-	overflow: auto;
-	overflow-x: auto;
+	/*overflow: auto;
+	overflow-x: auto;*/
 }
 
 .ivprog_textual_code {

+ 2 - 2
ivprog_menu/css/ivprog-visual-1.0.css

@@ -16,8 +16,8 @@ body {
 
 .ivprog_visual_panel, .ivprog_tab {
 	height: 96%;
-	overflow: auto;
-	overflow-x: auto;
+	/*overflow: auto;
+	overflow-x: auto;*/
 }
 
 .ivprog_functions_tab_panel {

+ 30 - 11
package-lock.json

@@ -2220,7 +2220,8 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -2241,12 +2242,14 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -2261,17 +2264,20 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -2388,7 +2394,8 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -2400,6 +2407,7 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -2414,6 +2422,7 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -2421,12 +2430,14 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -2445,6 +2456,7 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -2525,7 +2537,8 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -2537,6 +2550,7 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -2622,7 +2636,8 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -2658,6 +2673,7 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -2677,6 +2693,7 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -2720,12 +2737,14 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         }
       }
     },

+ 0 - 0
relatorio.php


+ 5 - 4
relatorio_aluno_exercicio.php

@@ -29,7 +29,9 @@ $qualVersao = qualVersaoDoIVProg($arquivoLogsAluno);
   <link href="css/bootstrap.min.css" rel="stylesheet" />
     <link href="css/style.css" rel="stylesheet" />
   <style>
-    #line-heatmap-canvas { width:91%; height:100%; position:absolute;}
+    #line-heatmap-canvas { width:1500px; height:1500px; position:absolute;}
+    #line-heatmap-view { width:1500px; height:1500px; position:absolute;}
+    #line-heatmap-tooltip { position:absolute; left:0; top:0; background:rgba(0,0,0,.8); color:white; font-size:14px; padding:5px; line-height:18px; display:none; z-index:10}
   </style>
   <title>Test</title>
   <script src="dist/line_heatmap.js"></script>
@@ -94,7 +96,6 @@ $qualVersao = qualVersaoDoIVProg($arquivoLogsAluno);
             <label for="inputexercicio" class="col-sm-2 col-form-label">Exercício:</label>
             <div class="col-sm-10">
               <select class="form-control" id="inputexercicio" name="exercicio">
-                <option value="Todos">Todos</option>
                 <?php
                   for ($i = 0; $i < count($exercicios); $i++) {
                     echo "<option value='$exercicios[$i]'" . ($exercicios[$i] == $_GET['exercicio']?" selected":"") . ">" . str_replace('_', ' ', $exercicios[$i]) . "</option>";
@@ -139,10 +140,10 @@ $qualVersao = qualVersaoDoIVProg($arquivoLogsAluno);
 	  ?>
   
 	  <script>
-	    line_heatmap.Container.init('hea',"<?= $logsAlunoString ?>");
+	    line_heatmap.Container.init('hea',"<?= $logsAlunoString ?>", true);
 	  </script>
 
-	  <iframe frameborder="0" name="iLM" src="ivprog_<?= $qualVersao ?>/index.html?1=1&iLM_PARAM_AssignmentURL=true&iLM_PARAM_Assignment=../temp/<?= $arquivoLogsAluno ?>&iLM_PARAM_SendAnswer=false&iLM_PARAM_ServerToGetAnswerURL=&lang=pt" <?= ($qualVersao == "menu"?"style='width: 1400px; height: 800px;'":"style='width: 800px; height: 600px;'") ?> >
+	  <iframe frameborder="0" name="iLM" src="ivprog_<?= $qualVersao ?>/index.html?1=1&iLM_PARAM_AssignmentURL=true&iLM_PARAM_Assignment=../temp/<?= $arquivoLogsAluno ?>&iLM_PARAM_SendAnswer=false&iLM_PARAM_ServerToGetAnswerURL=&lang=pt" <?= ($qualVersao == "menu"?"style='width: 1400px; height: 1500px;'":"style='width: 800px; height: 1500px;'") ?> >
 	</iframe>
 
   <?php

+ 162 - 0
relatorio_exercicio.php

@@ -0,0 +1,162 @@
+<?php
+
+require 'functions.php';
+
+$cursos = listarCursos();
+$alunos = listarAlunos($_GET['curso']);
+$exercicios = listarExercicios($_GET['curso']);
+
+$curso_selecionado = $_GET['curso'];
+// $aluno_selecionado = $_GET['aluno'];
+$exercicio_selecionado = $_GET['exercicio'];
+
+?>
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>ivprog_log_analysis</title>
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <link rel="stylesheet" href="dist/style.css">
+  <link href="css/bootstrap.min.css" rel="stylesheet" />
+    <link href="css/style.css" rel="stylesheet" />
+  <style>
+    #line-heatmap-canvas { width:1200px; height:1200px; position:absolute;}
+    #line-heatmap-view { width:1200px; height:1200px; position:absolute;}
+    #line-heatmap-tooltip { position:absolute; left:0; top:0; background:rgba(0,0,0,.8); color:white; font-size:14px; padding:5px; line-height:18px; display:none; z-index:10}
+  </style>
+  <title>Test</title>
+  <script src="dist/line_heatmap.js"></script>
+  <style type="text/css">
+  </style>
+</head>
+<body>
+
+	<nav class="navbar navbar-expand-md navbar-dark fixed-top" style="background-color: #03396c;">
+      <b><a class="navbar-brand" href="./">ivprog_log_analysis - Ambiente de análise dos logs do iVProgH</a></b>
+      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
+        <span class="navbar-toggler-icon"></span>
+      </button>
+      <div class="collapse navbar-collapse" id="navbarsExampleDefault">
+        <ul class="navbar-nav mr-auto">
+          <li class="nav-item active">
+            <a class="nav-link" href="./" title=""></a>
+          </li>
+          </ul>
+      </div>
+    </nav>
+
+    <main role="main">
+      <div class="jumbotron ivprogh-desc">
+        <div class="container">
+          <?= instrucoes() ?>
+        </div>
+      </div>
+
+
+      <div class="container ivprog-container" style="padding: 3em; margin-top: 3em;">
+        <form action="process.php" method="get" novalidate>
+
+          <div class="form-group row">
+            <label for="inputname" class="col-sm-2 col-form-label">Curso:</label>
+            <div class="col-sm-10">
+              <select class="form-control" id="inputname" name="curso">
+                <?php
+                  for ($i = 0; $i < count($cursos); $i++) {
+                    echo "<option" . ($cursos[$i] == $_GET['curso']?" selected":"") . ">" . $cursos[$i] . "</option>";
+                  }
+                ?>
+              </select>
+            </div>
+          </div>
+
+          <div class="form-group row">
+            <label for="inputaluno" class="col-sm-2 col-form-label">Aluno:</label>
+            <div class="col-sm-10">
+              <select class="form-control" id="inputaluno" name="aluno">
+                <option>Todos</option>
+                <?php
+                  for ($i = 0; $i < count($alunos); $i++) {
+                    echo "<option value='$alunos[$i]'" . ($alunos[$i] == $_GET['aluno']?" selected":"") . ">" . str_replace('_', ' ', $alunos[$i]) . "</option>";
+                  }
+                ?>
+              </select>
+            </div>
+        </div>
+
+      <div class="form-group row">
+            <label for="inputexercicio" class="col-sm-2 col-form-label">Exercício:</label>
+            <div class="col-sm-10">
+              <select class="form-control" id="inputexercicio" name="exercicio">
+                <?php
+                  for ($i = 0; $i < count($exercicios); $i++) {
+                    echo "<option value='$exercicios[$i]'" . ($exercicios[$i] == $_GET['exercicio']?" selected":"") . ">" . str_replace('_', ' ', $exercicios[$i]) . "</option>";
+                  }
+                ?>
+              </select>
+            </div>
+        </div>
+
+      <div class="form-group row">
+          <div class="offset-sm-2 col-sm-10">
+            <button type="button" class="btn btn-secondary" onclick="window.history.back();">Voltar</button>
+            <button type="submit" class="btn btn-primary">Continuar</button>
+            <span class="reported" style="color: green; font-size: 120%;"></span>
+            <span class="error" style="color: red; font-size: 120%;"></span>
+          </div>
+        </div>
+
+        </form>
+      </div>
+
+      <div>
+        
+      </div>
+    </main>
+    <script src="./js/jquery.min.js"></script>
+    <script src="./js/bootstrap.bundle.min.js"></script>
+
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css">
+
+
+  <div>
+    <div id="hea">
+    </div>
+ 
+
+	  <?php
+      $arquivoLogsAluno = null;
+      
+      $logsTodosAlunos = "";
+      for ($i=0; $i < count($alunos); ++$i) { 
+        $tempAluno = $alunos[$i];
+        $tempArquivoLogsAluno = pegarLogsDoAluno($curso_selecionado, $tempAluno, $exercicio_selecionado);
+        $logAluno = pegarLogsDoAlunoComoString($tempArquivoLogsAluno);
+        if(!empty($logAluno) && is_null($arquivoLogsAluno)) {
+          $arquivoLogsAluno = $tempArquivoLogsAluno;
+        }
+        $logsTodosAlunos .= $logAluno;
+      }
+      $qualVersao = qualVersaoDoIVProg($arquivoLogsAluno);
+
+      if (is_null($arquivoLogsAluno)) {
+        echo "<center><h4>N&atilde;o houve submiss&otilde;es para o exerc&iacute;cio selecionado!</h4></center>";
+      } else {
+	  ?>
+  
+	  <script>
+	    line_heatmap.Container.init('hea',"<?= $logsTodosAlunos ?>", true);
+	  </script>
+
+	  <iframe frameborder="0" name="iLM" src="ivprog_<?= $qualVersao ?>/index.html?1=1&iLM_PARAM_AssignmentURL=true&iLM_PARAM_Assignment=../temp/<?= $arquivoLogsAluno ?>&iLM_PARAM_SendAnswer=false&iLM_PARAM_ServerToGetAnswerURL=&lang=pt" <?= ($qualVersao == "menu"?"style='width: 1400px; height: 1500px;'":"style='width: 800px; height: 1500px;'") ?> >
+	</iframe>
+  <?php
+      }
+  ?>
+ </div>
+
+
+</body>
+</html>

+ 170 - 7
src/heatContainer.js

@@ -6,25 +6,39 @@ const template = `<div>
     <div id="line-heatmap-slider"></div>
   </div>
   <div id="line-heatmap-canvas">
+    <div id="line-heatmap-view"></div>
+    <div id="line-heatmap-tooltip"></div>
   </div>
 </div>
 `;
 
+const cursorDist = 10;
+
 const stateObject = {};
 
-function init (elementId, logString) {
+let x1, y1, x2, y2;
+let firstClick = true;
+let div = null;
+
+let posLeft;
+let posTop;
+let yBottom;
+let xBottom;
+
+function init (elementId, logString, useTooltip = false, config = {}) {
   const el = document.getElementById(elementId);
   el.innerHTML = template;
   const logData = logTransform(logString);
   // create container
-  const heatmap = new LineHeatmap('line-heatmap-canvas');
-  heatmap.create();
+  const heatmap = new LineHeatmap('line-heatmap-view');
+  heatmap.create(config);
   heatmap.setTrackData(logData);
 
   const html5Slider = document.getElementById('line-heatmap-slider');
   noUiSlider.create(html5Slider, {
       start: [1, logData.length],
       connect: true,
+      step: 1,
       margin: 1,
       range: {
           'min': 1,
@@ -37,12 +51,40 @@ function init (elementId, logString) {
   stateObject['data'] = logData;
   stateObject['slider'] = html5Slider;
 
+  if (useTooltip) {
+    registerClickEvent();
+    const canvasWrapper = document.getElementById('line-heatmap-canvas');
+    const tooltip = document.getElementById('line-heatmap-tooltip');
+    function updateTooltip (x, y, value) {
+      const transl = `translate(${x + cursorDist}px, ${y + cursorDist}px)`;
+      tooltip.style.webkitTransform = transl;
+      tooltip.innerHTML = `(${x},${y},${value})`;
+    };
+
+    canvasWrapper.onmousemove = function (ev) {
+      var x = ev.layerX;
+      var y = ev.layerY;
+      // getValueAt gives us the value for a point p(x/y)
+      var value = stateObject['heatmap'].instance.getValueAt({
+        x: x, 
+        y: y
+      });
+      tooltip.style.display = 'block';
+      updateTooltip(x, y, value);
+    };
+    // hide tooltip on mouseout
+    canvasWrapper.onmouseout = function() {
+      tooltip.style.display = 'none';
+    };
+    /* tooltip code end */
+  }
+
   html5Slider.noUiSlider.on('update', function (values, handle) {
     const logValues = this.get();
-    console.log(logValues);
     const newData = stateObject['data'].slice(+logValues[0]-1, +logValues[1] + 1);
-    console.log(newData);
     stateObject['heatmap'].setTrackData(newData);
+    if(div !== null)
+      updateDivText(div, posLeft, posTop, xBottom, yBottom);
   });
 }
 
@@ -58,6 +100,25 @@ function updateLogString (logString) {
   stateObject['heatmap'].setTrackData(logData); 
 }
 
+function countClicks (x1, y1, x2, y2) {
+  const instance = stateObject['heatmap'].instance;
+  const points = instance.getData().data;
+  let counter = 0;
+  for(let i = 0; i < points.length; ++i) {
+    const point = points[i];
+    if (point.x >= x1 && point.y >= y1) {
+      if (point.x <= x2 && point.y <= y2) {
+        counter += point.value;
+      }
+    }
+  }
+  return counter;
+}
+
+function totalClicks () {
+  return stateObject['data'].length;
+}
+
 function logTransform (logString) {
   const data = logString.split("\n")
   .filter(v => v.split(',').length > 3)
@@ -72,7 +133,109 @@ function logTransform (logString) {
   return data;
 }
 
+function registerClickEvent () {
+  const elemen = document.querySelector(".heatmap-canvas");
+  window.onclick = function (evt) {
+    if(evt.target !== elemen) {
+      return;
+    }
+    if (firstClick) {
+      if (evt.pageX || evt.pageY) {
+        x1 = evt.pageX;
+        y1 = evt.pageY;
+      } else {
+        x1 = evt.clientX + document.body.scrollLeft + elemen.scrollLeft;
+        y1 = evt.clientY + document.body.scrollTop + elemen.scrollTop;
+      }
+      x1 -= elemen.offsetLeft;
+      y1 -= elemen.offsetTop;
+      firstClick = false;
+    } else {
+      if (evt.pageX || evt.pageY) {
+        x2 = evt.pageX;
+        y2 = evt.pageY;
+      } else {
+        x2 = evt.clientX + document.body.scrollLeft + elemen.scrollLeft;
+        y2 = evt.clientY + document.body.scrollTop + elemen.scrollTop;
+      }
+      x2 -= elemen.offsetLeft;
+      y2 -= elemen.offsetTop;
+
+      firstClick = true;
+      if (div !== null) {
+        document.getElementById("line-heatmap-canvas").removeChild(div);
+        div = null;
+      }
+      div = document.createElement("div");
+      posLeft = Math.min(x1,x2);
+      posTop = Math.min(y1,y2) - 585;
+      yBottom = Math.max(y1,y2) - 585;
+      xBottom = Math.max(x1,x2);
+      const width = Math.abs(xBottom - posLeft);
+      const height = Math.abs(yBottom - posTop);
+      updateDivText(div, posLeft, posTop, xBottom, yBottom);
+      div.style.width = width + "px";
+      div.style.height = height + "px";
+      div.style.position = "absolute";
+      div.style.top = posTop + "px";
+      div.style.left = posLeft + "px";
+      div.style.border = "1px solid green";
+      document.getElementById("line-heatmap-canvas").append(div);
+      
+    }
+  }
+}
+
+function updateDivText (div, posLeft, posTop, xBottom, yBottom) {
+  const count = countClicks(posLeft, posTop, xBottom, yBottom);
+  const ratio = count/totalClicks();
+  div.innerHTML = `<span style="font-size:14px">Quantidade de clicks: ${count}</span>
+  <span style="font-size:14px">Proporção em relação ao total: ${ratio}</span>`;
+}
+
+
 export default {
   init,
-  updateLogString
-}
+  updateLogString,
+  countClicks,
+  totalClicks
+}
+
+/**
+ var x1, y1, x2, y2;
+var sequencia = 1;
+
+window.onclick = function(evt) {
+    var elemen = document.querySelector(".heatmap-canvas");
+    if (sequencia == 1) {
+     if (evt.pageX || evt.pageY) {
+        x1 = evt.pageX;
+        y1 = evt.pageY;
+     } else {
+        x1 = evt.clientX + document.body.scrollLeft + elemen.scrollLeft;
+        y1 = evt.clientY + document.body.scrollTop + elemen.scrollTop;
+       }
+     x1 -= elemen.offsetLeft;
+       y1 -= elemen.offsetTop;
+       sequencia ++;
+    } else {
+      if (evt.pageX || evt.pageY) {
+        x2 = evt.pageX;
+        y2 = evt.pageY;
+     } else {
+        x2 = evt.clientX + document.body.scrollLeft + elemen.scrollLeft;
+        y2 = evt.clientY + document.body.scrollTop + elemen.scrollTop;
+       }
+    x2 -= elemen.offsetLeft;
+       y2 -= elemen.offsetTop;
+       
+      var width = Math.abs(x2 - x1);
+      var height = Math.abs(y2 - y1);
+      sequencia = 1;
+
+
+        $('#line-heatmap-canvas').append($('<div style="position: absolute; border: 1px solid green; top: '+(y1 - 580)+'px; left: '+x1+'px; width: '+width+'px; height: '+height+'px; "></div>'));
+            
+    }
+}
+ */

+ 4 - 0
src/lineHeatmap.js

@@ -7,6 +7,10 @@ export default class LineHeatmap {
     this.heatmap = null;
   }
 
+  get instance () {
+    return this.heatmap;
+  }
+
   create (config = {}) {
     let myConfig = {
       container: document.getElementById(this.ID)

Файловите разлики са ограничени, защото са твърде много
+ 0 - 1869
temp/1.4_Pratica_-_Idade-2019_01_21_10_32.ivph