From 87f75ea2869629fedf893942b767765eff40c597 Mon Sep 17 00:00:00 2001 From: n-peugnet Date: Sun, 22 Mar 2020 16:30:35 +0100 Subject: very first graph displayed using cytoscape --- src/map.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/map.js (limited to 'src') diff --git a/src/map.js b/src/map.js new file mode 100644 index 0000000..5561250 --- /dev/null +++ b/src/map.js @@ -0,0 +1,9 @@ +import cytoscape from 'cytoscape'; + +let options = { + container: document.getElementById('graph'), +}; + +Object.assign(options, data); + +let cy = cytoscape(options); -- cgit v1.2.3 From 86d0185d570dbc896f9f438c12e133e8cdd83940 Mon Sep 17 00:00:00 2001 From: n-peugnet Date: Mon, 23 Mar 2020 15:13:09 +0100 Subject: feat(graph): better layout with cose-bilkent --- app/class/Modelhome.php | 2 +- package-lock.json | 21 +++++++++++++++++++++ package.json | 3 ++- src/map.js | 3 +++ 4 files changed, 27 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/app/class/Modelhome.php b/app/class/Modelhome.php index f4b4a56..343a879 100644 --- a/app/class/Modelhome.php +++ b/app/class/Modelhome.php @@ -156,7 +156,7 @@ class Modelhome extends Modelpage } $datas['elements'] = array_merge($nodes, $edges); - $datas['layout']['name'] = 'random'; + $datas['layout']['name'] = 'cose-bilkent'; $datas['style'] = [ [ 'selector' => 'node', diff --git a/package-lock.json b/package-lock.json index 939fd83..5302d80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1336,6 +1336,14 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cose-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.1.tgz", + "integrity": "sha512-LErvsHUOzYseXGFKWGCAQBTePO1iYZ9JL+YZlmoyqZ7EDcBzrEMRSouOGszQl72J6VK0AVrJbnNCf3eciqy7SA==", + "requires": { + "layout-base": "^1.0.0" + } + }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -1476,6 +1484,14 @@ "lodash.debounce": "^4.0.8" } }, + "cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "requires": { + "cose-base": "^1.0.0" + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -3566,6 +3582,11 @@ "package-json": "^6.3.0" } }, + "layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", diff --git a/package.json b/package.json index 5cec8c8..0448346 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "license": "MIT", "dependencies": { "codemirror": "^5.49.0", - "cytoscape": "^3.14.1" + "cytoscape": "^3.14.1", + "cytoscape-cose-bilkent": "^4.1.0" }, "devDependencies": { "@sentry/browser": "^5.9.0", diff --git a/src/map.js b/src/map.js index 5561250..5da0e57 100644 --- a/src/map.js +++ b/src/map.js @@ -1,4 +1,7 @@ import cytoscape from 'cytoscape'; +import coseBilkent from 'cytoscape-cose-bilkent'; + +cytoscape.use(coseBilkent); let options = { container: document.getElementById('graph'), -- cgit v1.2.3 From 70266304bab399b827af4acab153daaa47a2ba93 Mon Sep 17 00:00:00 2001 From: n-peugnet Date: Mon, 23 Mar 2020 21:20:27 +0100 Subject: fix(home): checkall error when in map mode --- src/home.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/home.js b/src/home.js index 8906079..3dc79ef 100644 --- a/src/home.js +++ b/src/home.js @@ -3,6 +3,9 @@ import { checkallHandler, closeSubmenus } from './fn/fn'; window.addEventListener('load', () => { let checkboxes = document.getElementsByName('pagesid[]'); let checkall = document.getElementById('checkall'); + if (!checkall) { + return; + } let checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.addEventListener('input', checkallHandler.bind({ checkboxes })); -- cgit v1.2.3 From d17713051ca2fef29de8025fe876d417838cea7f Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Wed, 25 Mar 2020 19:53:38 +0100 Subject: graph look, add redirections, close #50 --- app/class/Config.php | 13 ++++- app/class/Controllerhome.php | 11 ++--- app/class/Modelhome.php | 106 +++++++++++++++++++++++++++-------------- app/class/Modelrender.php | 7 +-- app/view/templates/home.php | 8 ++-- app/view/templates/homeopt.php | 2 + src/map.js | 20 ++++++++ 7 files changed, 117 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/app/class/Config.php b/app/class/Config.php index fa9082f..2cfdcd3 100644 --- a/app/class/Config.php +++ b/app/class/Config.php @@ -3,6 +3,8 @@ namespace Wcms; +use Http\Client\Common\Plugin\RetryPlugin; + abstract class Config { protected static $pagetable = 'mystore'; @@ -129,9 +131,16 @@ abstract class Config return self::$fontsize; } - public static function basepath() + /** + * @param bool $trailingslash If not empty basepath, add a trailing slash after the basepath + */ + public static function basepath(bool $trailingslash = false) : string { - return self::$basepath; + if($trailingslash && !empty(self::$basepath)) { + return self::$basepath . '/'; + } else { + return self::$basepath; + } } public static function route404() diff --git a/app/class/Controllerhome.php b/app/class/Controllerhome.php index 6444ac2..71f110e 100644 --- a/app/class/Controllerhome.php +++ b/app/class/Controllerhome.php @@ -34,11 +34,7 @@ class Controllerhome extends Controllerpage $deepsearch = $this->deepsearch(); - $idlistfilter = $this->modelhome->filter($pagelist, $this->opt); - $pagelistfilter = $this->modelhome->pagelistfilter($pagelist, $idlistfilter); - $pagelistdeep = $this->modelhome->deepsearch($pagelistfilter, $deepsearch['regex'] , $deepsearch['searchopt']); - $pagelistsort = $this->modelhome->sort($pagelistdeep, $this->opt); - $vars['pagelistopt'] = $pagelistsort; + $vars['pagelistopt'] = $this->modelhome->pagetable($pagelist, $this->opt, $deepsearch['regex'], $deepsearch['searchopt']); $vars['columns'] = $this->modelhome->setcolumns($this->user->columns()); @@ -54,8 +50,9 @@ class Controllerhome extends Controllerpage if($vars['display'] === 'map') { $vars['layout'] = $_GET['layout'] ?? 'cose-bilkent'; - $vars['hideorphans'] = boolval($_GET['hideorphans'] ?? false); - $datas = $this->modelhome->cytodata($pagelistsort, $vars['layout'], $vars['hideorphans']); + $vars['showorphans'] = boolval($_GET['showorphans'] ?? false); + $vars['showredirection'] = boolval($_GET['showredirection'] ?? false); + $datas = $this->modelhome->cytodata($vars['pagelistopt'], $vars['layout'], $vars['showorphans'], $vars['showredirection']); $vars['json'] = json_encode($datas, JSON_PRETTY_PRINT); } diff --git a/app/class/Modelhome.php b/app/class/Modelhome.php index ede9179..949c4f7 100644 --- a/app/class/Modelhome.php +++ b/app/class/Modelhome.php @@ -39,6 +39,25 @@ class Modelhome extends Modelpage } + /** + * @param array $pagelist of Pages objects as `id => Page` + * @param Opt $opt + * + * @param string $regex Regex to match. + * @param array $options Option search, could be `content` `title` `description`. + * + * @return array associative array of `Page` objects * + */ + public function pagetable(array $pagelist, Opt $opt, $regex = '', $searchopt = []) : array + { + $pagelist = $this->filter($pagelist, $opt); + if(!empty($regex)) { + $pagelist = $this->deepsearch($pagelist, $regex , $searchopt); + } + $pagelist = $this->sort($pagelist, $opt); + + return $pagelist; + } @@ -66,28 +85,11 @@ class Modelhome extends Modelpage $filter = array_diff($idlist, $filter); } - return $filter; + return array_intersect_key($pagelist, array_flip($filter)); } - /** - * Convert list of id into a list of Page objects - * - * @param array $pagelist - * @param array $idlist - * - * @return array Filtered list of `Page` objects - */ - public function pagelistfilter(array $pagelist, array $fiter) : array - { - return array_intersect_key($pagelist, array_flip($fiter)); - } - - - - - /** * Sort and limit an array of Pages * @@ -160,13 +162,14 @@ class Modelhome extends Modelpage * * @param array $pagelist associative array of pages as `id => Page` * @param string $layout - * @param bool $hideorphans if `true`, remove orphans pages - * + * @param bool $showorphans if `false`, remove orphans pages + * @param bool $showredirection if `true`, add redirections * + * @return array */ - public function cytodata(array $pagelist, string $layout = 'random', bool $hideorphans = false) + public function cytodata(array $pagelist, string $layout = 'random', bool $showorphans = false, bool $showredirection = false) : array { - $datas['elements'] = $this->mapdata($pagelist, $hideorphans); + $datas['elements'] = $this->mapdata($pagelist, $showorphans, $showredirection); $datas['layout'] = [ 'name' => $layout, @@ -175,7 +178,7 @@ class Modelhome extends Modelpage 'randomize' => true, 'nodeDimensionsIncludeLabels' => true, 'tile' => false, - 'edgeElasticity' => 0.75, + 'edgeElasticity' => 0.45, 'gravity' => 0.25, 'idealEdgeLength' => 60, 'numIter' => 10000 @@ -185,6 +188,24 @@ class Modelhome extends Modelpage 'selector' => 'node', 'style' => [ 'label' => 'data(id)', + 'background-image' => 'data(favicon)', + 'background-fit' => 'contain', + 'border-width' => 3, + 'border-color' => '#80b97b' + ], + ], + [ + 'selector' => 'node.not_published', + 'style' => [ + 'shape' => 'round-hexagon', + 'border-color' => '#b97b7b' + ], + ], + [ + 'selector' => 'node.private', + 'style' => [ + 'shape' => 'round-triangle', + 'border-color' => '#b9b67b' ], ], [ @@ -192,6 +213,14 @@ class Modelhome extends Modelpage 'style' => [ 'curve-style' => 'bezier', 'target-arrow-shape' => 'triangle', + 'arrow-scale' => 1.5 + ], + ], + [ + 'selector' => 'edge.redirect', + 'style' => [ + 'line-style' => 'dashed', + 'label' => 'data(refresh)' ], ], ]; @@ -202,15 +231,17 @@ class Modelhome extends Modelpage * Transform list of Pages into cytoscape nodes and edge datas * * @param array $pagelist associative array of pages as `id => Page` - * @param bool $hideorphans if `true`, remove orphans pages - * + * @param bool $showorphans if `false`, remove orphans pages + * @param bool $showredirection if `true`, add redirections + * * @return array of cytoscape datas */ - public function mapdata(array $pagelist, bool $hideorphans = false) : array + public function mapdata(array $pagelist, bool $showorphans = true, bool $showredirection = false) : array { $idlist = array_keys($pagelist); $edges = []; + $notorphans = []; foreach ($pagelist as $page) { foreach ($page->linkto() as $linkto) { if(in_array($linkto, $idlist)) { @@ -220,9 +251,19 @@ class Modelhome extends Modelpage $edge['data']['target'] = $linkto; $edges[] = $edge; $notorphans[] = $linkto; + $notorphans[] = $page->id(); } } - if(!empty($page->linkto())) { + // add redirection edge + if($showredirection && key_exists($page->redirection(), $pagelist)) { + $edger['group'] = 'edges'; + $edger['data']['id'] = $page->id() . '>' . $page->redirection(); + $edger['data']['refresh'] = $page->refresh(); + $edger['data']['source'] = $page->id(); + $edger['data']['target'] = $page->redirection(); + $edger['classes'] = 'redirect'; + $edges[] = $edger; + $notorphans[] = $page->redirection(); $notorphans[] = $page->id(); } } @@ -231,16 +272,11 @@ class Modelhome extends Modelpage $nodes = []; foreach ($pagelist as $id => $page) { - if($hideorphans) { - if(in_array($id, $notorphans)) { - $node['group'] = 'nodes'; - $node['data']['id'] = $page->id(); - $node['classes'] = [$page->secure('string')]; - $nodes[] = $node; - } - } else { + if($showorphans || (!$showorphans && in_array($id, $notorphans))) { $node['group'] = 'nodes'; $node['data']['id'] = $page->id(); + $node['data']['edit'] = $page->id() . DIRECTORY_SEPARATOR . 'edit'; + $node['data']['favicon'] = Model::faviconpath() . $page->favicon(); $node['classes'] = [$page->secure('string')]; $nodes[] = $node; } diff --git a/app/class/Modelrender.php b/app/class/Modelrender.php index 2338eb4..638f3e3 100644 --- a/app/class/Modelrender.php +++ b/app/class/Modelrender.php @@ -7,6 +7,7 @@ use Michelf\MarkdownExtra; class Modelrender extends Modelpage { + /** @var \AltoRouter */ protected $router; /** @var Page */ protected $page; @@ -21,7 +22,7 @@ class Modelrender extends Modelpage const RENDER_VERBOSE = 1; - public function __construct($router) + public function __construct(\AltoRouter $router) { parent::__construct(); @@ -640,10 +641,10 @@ class Modelrender extends Modelpage foreach ($matches as $match) { $optlist = $modelhome->Optlistinit($pagelist); $optlist->parsehydrate($match['options']); - $table2 = $modelhome->table2($pagelist, $optlist, '', []); + $pagetable = $modelhome->pagetable($pagelist, $optlist, '', []); $content = '
    ' . PHP_EOL ; - foreach ($table2 as $page ) { + foreach ($pagetable as $page ) { $content .= '
  • ' . PHP_EOL; $content .= '' . $page->title() . '' . PHP_EOL; if($optlist->description()) { diff --git a/app/view/templates/home.php b/app/view/templates/home.php index 33bca81..482ce17 100644 --- a/app/view/templates/home.php +++ b/app/view/templates/home.php @@ -24,7 +24,7 @@
    - insert('homeopt', ['opt' => $opt, 'user' => $user]) ?> + insert('homeopt', ['opt' => $opt, 'user' => $user, 'display' => $display]) ?>
    @@ -39,8 +39,10 @@
    - > - + > + + > + diff --git a/app/view/templates/homeopt.php b/app/view/templates/homeopt.php index d1f70da..ed7315d 100644 --- a/app/view/templates/homeopt.php +++ b/app/view/templates/homeopt.php @@ -159,6 +159,8 @@
    + + diff --git a/src/map.js b/src/map.js index 5da0e57..4723318 100644 --- a/src/map.js +++ b/src/map.js @@ -10,3 +10,23 @@ let options = { Object.assign(options, data); let cy = cytoscape(options); + +cy.on('tap', 'node', function() { + try { + // your browser may block popups + window.open(this.data('id')); + } catch (e) { + // fall back on url change + window.location.href = this.data('id'); + } +}); + +cy.on('cxttap', 'node', function() { + try { + // your browser may block popups + window.open(this.data('edit')); + } catch (e) { + // fall back on url change + window.location.href = this.data('edit'); + } +}); -- cgit v1.2.3