Now history.timeline is vertical

This commit is contained in:
xdrm-brackets 2017-11-12 17:22:35 +01:00
parent 57d7abb7b6
commit 20baf93bf3
11 changed files with 350 additions and 275 deletions

View File

@ -10,8 +10,8 @@
class main extends i_view{ class main extends i_view{
public $id_history; public $id_history;
private $timeline = []; public $timeline = [];
private $entry = []; public $entry = [];
/* (1) Constructor /* (1) Constructor
@ -56,8 +56,6 @@
/* (2) Format timeline data to svg render /* (2) Format timeline data to svg render
* *
* @timeline<array> Timeline data
*
* @return svg<String> SVG raw render * @return svg<String> SVG raw render
* *
---------------------------------------------------------*/ ---------------------------------------------------------*/
@ -75,102 +73,86 @@
$c = 0; $c = 0;
$cl = count($this->timeline); $cl = count($this->timeline);
/* (4) Create ranges of size 15 */ /* (4) Useful variables */
$r_size = 10; // set the number of actions by line $y_pad = 80; // padding between each node
$rl = floor( $cl / $r_size ); // calculate the number of whole lines $line_pad = 50; // padding on each LINE end
$lrl = $cl % $r_size; // calculate the number of actions in the last line $line_height = ( $cl + 1 ) * $y_pad; // line height (each node * @y_pad + @y_pad)
$y_range_diff = 100; $height = $line_height + 2*$line_pad; // svg height
$total_height = ($lrl == 0 ) ? $y_range_diff*$rl : $y_range_diff*($rl+1); // total height (number of entries + last if not empty) $width = 100; // svg width
$x = $width/2; // center width
/* (5) Svg tag */ /* (5) Svg tag */
$RAW .= "<svg width='1000' height='$total_height' viewBox='0 0 1000 $total_height' class='timeline'>"; $RAW .= "<svg width='$width' height='$height' viewBox='0 0 $width $height' class='timeline'>";
/* (6) Start CIRCLE */ /* (6) Start CIRCLE */
$RAW .= "<circle cx='50' cy='50' r='6' fill='#edf0f5' class='tstart'/>"; $RAW .= "<circle cx='$x' cy='$line_pad' r='7' fill='#edf0f5' class='tstart'/>";
$RAW .= "<circle cx='50' cy='50' r='4' fill='#555' class='tstart'/>"; $RAW .= "<circle cx='$x' cy='$line_pad' r='4' fill='#555' class='tstart'/>";
for( $r = 0 ; $r <= $rl ; $r++ ){
// if last line is empty -> stop here
if( $r == $rl && $lrl == 0 )
break;
$y = $y_range_diff*$r + 50;
/* (2) Build barebone /* (2) Build barebone
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Default TIMELINE */ /* (1) Default TIMELINE */
if( $r < $rl ){ $line_end_y = $line_height + $line_pad;
$RAW .= "<path d='m$x $line_pad L$x $line_end_y' style='stroke-dasharray: 3px;' stroke='#444' class='timeline line'/>";
$RAW .= "<path d='m50 $y L900 $y' style='stroke-dasharray: 3px;' stroke='#444' class='timeline line'/>";
/* (2) Last TIMELINE (can be shorter) */
}else{ // if last line -> trace timeline until last element +1
$len = 100 + $lrl*800/$r_size;
$RAW .= "<path d='m50 $y L$len $y' style='stroke-dasharray: 3px;' stroke='#444' class='timeline line'/>";
}
/* (3) Build each action /* (3) Build each action
---------------------------------------------------------*/ ---------------------------------------------------------*/
$el_len = ( $r == $rl ) ? $lrl : $r_size ;// number of elements on the line for( $c = 0 ; $c < $cl ; $c++ ){
for( $c = 0 ; $c < $el_len ; $c++ ){
/* (1) Display nothing if last entry and is empty */ /* (1) Calculate X */
if( !isset($this->timeline[$r*$r_size+$c]) ) $y = $line_pad + $y_pad + $c*$y_pad;
break;
/* (2) Get entry data */ /* (2) Get entry data */
$entry = $this->timeline[$r*$r_size+$c]; $entry = $this->timeline[$c];
/* (3) Get useful data */ /* (3) Get useful data */
$action_class = strtolower($entry['action_name']); $action_class = strtolower($entry['action_name']);
$icon_uri = '/src/static/timeline/'.$action_class.'@'.$this->get_action_color($action_class).'.svg'; $icon_uri = '/src/static/timeline/'.$action_class.'@'.$this->get_action_color($action_class).'.svg';
$x_offset = 100 + $c*800/$r_size; $data_user = "data-user='".$entry['user_name']."'";
$x_img_offset = $x_offset - 5.5; $data_machine = " data-machine='".$entry['machine_name']."'";
$data_user = "data-user='".$entry['id_user']."'"; $data_action = " data-action='".$entry['action_name']."'";
$data_machine = " data-machine='".$entry['id_machine']."'";
$data_action = " data-action='".$entry['id_action']."'";
$data_time = " data-time='".date('H:i:s d/m/Y', $entry['timestamp'])."'"; $data_time = " data-time='".date('H:i:s d/m/Y', $entry['timestamp'])."'";
$data_tags = $data_user.$data_machine.$data_action.$data_time; $data_tags = $data_user.$data_machine.$data_action.$data_time;
$y_img = $y - 5.5;
/* (4) Draw entry circles */ /* (4) Draw entry circles */
$RAW .= "<circle cx='$x_offset' cy='$y' r='15' class='timeline around $action_class' $data_tags />"; $RAW .= "<circle cx='$x' cy='$y' r='15' class='timeline around $action_class' $data_tags />";
$RAW .= "<circle cx='$x_offset' cy='$y' r='12' class='timeline center $action_class' />"; $RAW .= "<circle cx='$x' cy='$y' r='12' class='timeline center $action_class' />";
/* (5) Draw entry icon (action) */ /* (5) Draw entry icon (action) */
$y_decal = $y - 5.5; $x_decal = $x - 5.5;
$RAW .= "\t<image x='$x_img_offset' y='$y_decal' width='12' height='12' xlink:href='$icon_uri' class='icon' />"; $RAW .= "\t<image x='$x_decal' y='$y_img' width='12' height='12' xlink:href='$icon_uri' class='icon' />";
/* (6) Draw circle below if current user */ /* (6) Draw circle below if current user */
if( $this->entry['id_user'] == $entry['id_user'] ){ if( $this->entry['id_user'] == $entry['id_user'] ){
$y_decal = $y + 21; $x_decal = $x - 21;
$RAW .= "<circle cx='$x_offset' cy='$y_decal' r='2' class='timeline below $action_class' />"; $RAW .= "<circle cx='$x_decal' cy='$y' r='2' class='timeline below $action_class' />";
} }
} }
}
/* (4) Close SVG /* (4) Close SVG
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Stop CIRCLE */ /* (1) Stop CIRCLE */
$x_offset = 100 + $c*800/$r_size; $y = $line_height + $line_pad;
$RAW .= "<circle cx='$x_offset' cy='$y' r='6' fill='#edf0f5' class='tstop' />"; $RAW .= "<circle cx='$x' cy='$y' r='6' fill='#edf0f5' class='tstop' />";
$RAW .= "<circle cx='$x_offset' cy='$y' r='4' fill='#555' class='tstop' />"; $RAW .= "<circle cx='$x' cy='$y' r='4' fill='#555' class='tstop' />";
/* (2) Close SVG tag */ /* (2) Close SVG tag */
$RAW .= "</svg>"; $RAW .= "</svg>";
/* (5) Create invisible infobox (for now)
---------------------------------------------------------*/
$RAW .= "<div class='timeline infobox'></div>";
return $RAW; return $RAW;
} }

View File

@ -1,3 +1,6 @@
<!-- <span class='in-dev'>In development.. This feature will soon be available.</span> --> <!-- <span class='in-dev'>In development.. This feature will soon be available.</span> -->
<article class='timeline container' data-length='{{ core.timeline | length }}'>
{{ core.svg() | raw }} {{ core.svg() | raw }}
</article>

View File

@ -17,6 +17,7 @@ $form-grey-color: #8d8d8d;
/* GESTION DES LONGUEURS */ /* GESTION DES LONGUEURS */
$menu-side-width: 4em; $menu-side-width: 4em;
$sub-menu-side-width: 7.5em;
// POUR RESOURCE_DISPATCHER // POUR RESOURCE_DISPATCHER

View File

@ -458,7 +458,7 @@
}
/* [4] Tableau à cocher /* [4] Tableau à cocher
=========================================================*/ =========================================================*/
@ -538,8 +538,18 @@ article.check-table{
/* [4] Timeline SVG /* [5] Timeline SVG
=========================================================*/ =========================================================*/
article.timeline.container{
display: block;
position: absolute;
width: calc( 100vw - #{$menu-side-width} - #{$sub-menu-side-width} - 11em );
flex: 1em;
overflow: hidden;
// overflow-x: auto;
svg.timeline{ svg.timeline{
/* (1) svg circles -> set right transform-origin */ /* (1) svg circles -> set right transform-origin */
@ -564,8 +574,8 @@ svg.timeline{
&:hover + .center + image + .below{ // below node &:hover + .center + image + .below{ // below node
-webkit-transform: translateY(100%); -webkit-transform: translateX(-100%);
transform: translateY(100%); transform: translateX(-100%);
} }
@ -604,3 +614,33 @@ svg.timeline{
} }
} }
/* (8) Timeline infobox */
div.timeline.infobox{
display: none;
position: absolute;
top: 80px;
left: 0;
width: auto;
height: auto;
padding: .5em 1em;
border: 1px solid #b1b6c0;
border-radius: 3px;
background: #d8deea;
color: #444;
&.active{
display: block;
}
}
}
}

View File

@ -68,7 +68,7 @@
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
overflow-x: none; overflow: hidden;
overflow-y: auto; overflow-y: auto;
} }

View File

@ -10,6 +10,10 @@
/* [2] INLINE-BOX pour afficher les listes de donnees /* [2] INLINE-BOX pour afficher les listes de donnees
=========================================================*/ =========================================================*/
/* [2-2] INLINE-ROW pour afficher des lignes /* [2-2] INLINE-ROW pour afficher des lignes
=========================================================*/
/* [4] Tableau à cocher
=========================================================*/
/* [5] Timeline SVG
=========================================================*/ } =========================================================*/ }
#WRAPPER > #CONTAINER > section { #WRAPPER > #CONTAINER > section {
display: none; display: none;
@ -539,17 +543,14 @@
#WRAPPER > #CONTAINER > section > .inline-row button { #WRAPPER > #CONTAINER > section > .inline-row button {
flex: auto; flex: auto;
width: 5em; } width: 5em; }
#WRAPPER > #CONTAINER article.check-table {
/* [4] Tableau à cocher
=========================================================*/
article.check-table {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
border-radius: 3px; border-radius: 3px;
border: 1px solid #ddd; } border: 1px solid #ddd; }
article.check-table > div { #WRAPPER > #CONTAINER article.check-table > div {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -561,18 +562,18 @@ article.check-table {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
transition: background .2s ease-in-out; transition: background .2s ease-in-out;
overflow: hidden; } overflow: hidden; }
article.check-table > div:nth-child(2n) { #WRAPPER > #CONTAINER article.check-table > div:nth-child(2n) {
background: #fdfdfd; } background: #fdfdfd; }
article.check-table > div > span { #WRAPPER > #CONTAINER article.check-table > div > span {
flex: 100%; flex: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: center; justify-content: center;
/* (1) Gestion du checkbox hack */ } /* (1) Gestion du checkbox hack */ }
article.check-table > div > span input[type='checkbox'] { #WRAPPER > #CONTAINER article.check-table > div > span input[type='checkbox'] {
display: none; } display: none; }
article.check-table > div > span input[type='checkbox'] + label[for] { #WRAPPER > #CONTAINER article.check-table > div > span input[type='checkbox'] + label[for] {
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 1.2em; width: 1.2em;
@ -581,15 +582,19 @@ article.check-table {
background-size: 100% auto; background-size: 100% auto;
transition: box-shadow .2s ease-in-out; transition: box-shadow .2s ease-in-out;
cursor: pointer; } cursor: pointer; }
article.check-table > div > span input[type='checkbox']:checked + label[for] { #WRAPPER > #CONTAINER article.check-table > div > span input[type='checkbox']:checked + label[for] {
background-image: url("/src/static/container/checkbox@checked@007dd8.svg"); } background-image: url("/src/static/container/checkbox@checked@007dd8.svg"); }
#WRAPPER > #CONTAINER article.timeline.container {
/* [4] Timeline SVG display: block;
=========================================================*/ position: absolute;
svg.timeline { width: calc( 100vw - 4em - 7.5em - 11em);
flex: 1em;
overflow: hidden;
/* (8) Timeline infobox */ }
#WRAPPER > #CONTAINER article.timeline.container svg.timeline {
/* (1) svg circles -> set right transform-origin */ /* (1) svg circles -> set right transform-origin */
/* (7) Avoid icons inside center circles to block :hover */ } /* (7) Avoid icons inside center circles to block :hover */ }
svg.timeline circle.timeline { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline {
-webkit-transform-origin: 50% 50% 0; -webkit-transform-origin: 50% 50% 0;
transform-origin: 50% 50% 0; transform-origin: 50% 50% 0;
transition: transform .2s ease-in-out; transition: transform .2s ease-in-out;
@ -597,35 +602,49 @@ svg.timeline {
/* (4) Remove center circle event */ /* (4) Remove center circle event */
/* (5) Set colors according to action type */ /* (5) Set colors according to action type */
/* (6) Make around circles a bit transparent */ } /* (6) Make around circles a bit transparent */ }
svg.timeline circle.timeline.around { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around {
cursor: pointer; cursor: pointer;
/* (3) Dispatch event to next nodes */ } /* (3) Dispatch event to next nodes */ }
svg.timeline circle.timeline.around:hover + .center { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around:hover + .center {
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
transform: scale(1.2); } transform: scale(1.2); }
svg.timeline circle.timeline.around:hover + .center + image + .below { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around:hover + .center + image + .below {
-webkit-transform: translateY(100%); -webkit-transform: translateX(-100%);
transform: translateY(100%); } transform: translateX(-100%); }
svg.timeline circle.timeline.center { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center {
-webkit-pointer-events: none; -webkit-pointer-events: none;
pointer-events: none; } pointer-events: none; }
svg.timeline circle.timeline.around.start, svg.timeline circle.timeline.center.start, svg.timeline circle.timeline.below.start { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.start, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.start, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.start {
fill: #2cde8b; } fill: #2cde8b; }
svg.timeline circle.timeline.around.stop, svg.timeline circle.timeline.center.stop, svg.timeline circle.timeline.below.stop { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.stop, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.stop, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.stop {
fill: #3a3a3a; } fill: #3a3a3a; }
svg.timeline circle.timeline.around.lock, svg.timeline circle.timeline.center.lock, svg.timeline circle.timeline.below.lock { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.lock, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.lock, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.lock {
fill: #e04343; } fill: #e04343; }
svg.timeline circle.timeline.around.unlock, svg.timeline circle.timeline.center.unlock, svg.timeline circle.timeline.below.unlock { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.unlock, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.unlock, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.unlock {
fill: #af1c1c; } fill: #af1c1c; }
svg.timeline circle.timeline.around.signal, svg.timeline circle.timeline.center.signal, svg.timeline circle.timeline.below.signal { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.signal, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.signal, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.signal {
fill: #3258d8; } fill: #3258d8; }
svg.timeline circle.timeline.around.unsignal, svg.timeline circle.timeline.center.unsignal, svg.timeline circle.timeline.below.unsignal { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around.unsignal, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.center.unsignal, #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.below.unsignal {
fill: #2041ab; } fill: #2041ab; }
svg.timeline circle.timeline.around { #WRAPPER > #CONTAINER article.timeline.container svg.timeline circle.timeline.around {
opacity: .6; } opacity: .6; }
svg.timeline image { #WRAPPER > #CONTAINER article.timeline.container svg.timeline image {
-webkit-pointer-events: none; -webkit-pointer-events: none;
pointer-events: none; } pointer-events: none; }
#WRAPPER > #CONTAINER article.timeline.container div.timeline.infobox {
display: none;
position: absolute;
top: 80px;
left: 0;
width: auto;
height: auto;
padding: .5em 1em;
border: 1px solid #b1b6c0;
border-radius: 3px;
background: #d8deea;
color: #444; }
#WRAPPER > #CONTAINER article.timeline.container div.timeline.infobox.active {
display: block; }
/*# sourceMappingURL= container.css.map */ /*# sourceMappingURL= container.css.map */

View File

@ -51,7 +51,7 @@
padding: 1em; padding: 1em;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
overflow-x: none; overflow: hidden;
overflow-y: auto; } overflow-y: auto; }
#WRAPPER > #POPUP { #WRAPPER > #POPUP {
display: none; display: none;

View File

@ -9,7 +9,7 @@
& > span[data-sublink]{ & > span[data-sublink]{
display: block; display: block;
position: relative; position: relative;
width: 7.5em; width: $sub-menu-side-width;
padding: .3em 1em .3em 2em; padding: .3em 1em .3em 2em;
margin: 1em; margin: 1em;

View File

@ -105,14 +105,6 @@ Element.prototype.anim = function(className, timeout){
}; };
// RECUPERATION DE LA POSITION ABSOLUE D'UN ENFANT PAR RAPPORT A UN PARENT
Element.prototype.get_parent_abs = function(parent_node){
}
/* DEFINITION DES FORMATS UTILES POUR INPUT-CHECKER /* DEFINITION DES FORMATS UTILES POUR INPUT-CHECKER
* *
*/ */

View File

@ -72,7 +72,7 @@
/* [3] Archive -> Archivage des logs /* [3] Archive -> Archivage des logs
=========================================================*/ =========================================================*/
echo "<section data-sublink='archive'>"; echo "<section data-sublink='archive' class='fstart'>";
$view = View::load('history.archive'); $view = View::load('history.archive');
echo $view->render(); echo $view->render();

View File

@ -165,26 +165,64 @@ if( section.details.element != null ){
/* (1) Get useful DOM Elements /* (1) Get useful DOM Elements
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Get parent */
section.details.parent = {
text: section.details.text+'article.timeline.container ',
element: document.querySelector( section.details.text+'article.timeline.container ' )
};
/* (2) Get SVG tag */
section.details.svg = {
text: section.details.parent.text+'svg.timeline ',
element: document.querySelector( section.details.parent.text+'svg.timeline ' )
};
/* (3) Get each event node */
section.details.event = { section.details.event = {
// svg parent text: section.details.svg.text+'circle.around ',
parent: { list: document.querySelectorAll( section.details.svg.text+'circle.around ' )
text: section.details.text+' svg ',
element: document.querySelector( section.details.text+' svg ' )
},
// each node
text: section.details.text+' svg circle.around ',
element: document.querySelectorAll( section.details.text+' svg circle.around ' )
}; };
/* (2) Function: show infobox on click on event /* (4) Get infobox node */
section.details.info = {
text: section.details.parent.text+'div.timeline.infobox ',
element: document.querySelector( section.details.parent.text+'div.timeline.infobox ' )
};
/* (5) Bind infobox sub-elements */
section.details.info.input = {
};
/* (2) Function: scroll-x on mouse hover
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Bind slider event */
section.details.parent.element.addEventListener('mousemove', function(e){
var container = e.target.parentNode;
console.log(e.clientX-container.offsetLeft, e.clientY-container.offsetTop);
}, false);
/* (3) Function: show infobox on click on event
---------------------------------------------------------*/
/* (1) Set click handler */
section.details.event.handler = function(target){ section.details.event.handler = function(target){
section.details.info.element.addClass('active');
console.log('show infobox on element', target); console.log('show infobox on element', target);
}; };
/* (n) Trigger event */ /* (2) Trigger event */
section.details.event.parent.element.addEventListener('click', function(e){ section.details.svg.element.addEventListener('click', function(e){
// {1} Trigger function only if element is an 'around circle' // // {1} Trigger function only if element is an 'around circle' //
if( e.target.nodeName && e.target.getData('user') && e.target.getData('machine') && e.target.getData('action') && e.target.getData('time') ) if( e.target.nodeName && e.target.getData('user') && e.target.getData('machine') && e.target.getData('action') && e.target.getData('time') )