Difference between revisions of "Diagrams"
(34 intermediate revisions by the same user not shown) | |||
Line 9: | Line 9: | ||
= What is it ? = | = What is it ? = | ||
This is a Python based webservice to render diagrams for | This is a Python based webservice to render diagrams for | ||
− | + | * [[File:GraphVizLogo.png|link=https://www.graphviz.org/|graphviz]][https://www.graphviz.org graphviz] | |
− | + | * [[File:Msc-sig.png|link=http://www.mcternan.me.uk/mscgen/|mscgen]][http://www.mcternan.me.uk/mscgen mscgen] | |
− | + | * [[File:Plantuml logo.png|link=https://plantuml.com/|plantuml]][https://plantuml.com/ plantuml] | |
= Demo = | = Demo = | ||
https://diagrams.bitplan.com | https://diagrams.bitplan.com | ||
= Examples = | = Examples = | ||
− | = | + | {| class="wikitable sortable" |
− | <graphviz> | + | |- |
+ | ! tool !! source !! image | ||
+ | |- | ||
+ | | dot | ||
+ | | <pre><graphviz> | ||
graph development { | graph development { | ||
Stakeholder -- Requirements; | Stakeholder -- Requirements; | ||
Line 25: | Line 29: | ||
} | } | ||
</graphviz> | </graphviz> | ||
+ | </pre> | ||
+ | | <graphviz> | ||
+ | graph development { | ||
+ | Stakeholder -- Requirements; | ||
+ | Requirements -- Samplecases; | ||
+ | Requirements -- Model; | ||
+ | Model -- Code; | ||
+ | } | ||
+ | </graphviz> | ||
+ | |- | ||
+ | | neato | ||
+ | |<pre><graphviz renderer='neato'> | ||
+ | graph G { | ||
+ | run -- intr; | ||
+ | intr -- runbl; | ||
+ | runbl -- run; | ||
+ | run -- kernel; | ||
+ | kernel -- zombie; | ||
+ | kernel -- sleep; | ||
+ | kernel -- runmem; | ||
+ | sleep -- swap; | ||
+ | swap -- runswap; | ||
+ | runswap -- new; | ||
+ | runswap -- runmem;n | ||
+ | new -- runmem; | ||
+ | sleep -- runmem; | ||
+ | } | ||
+ | </graphviz> | ||
+ | </pre> | ||
+ | |<graphviz renderer='neato'> | ||
+ | graph G { | ||
+ | run -- intr; | ||
+ | intr -- runbl; | ||
+ | runbl -- run; | ||
+ | run -- kernel; | ||
+ | kernel -- zombie; | ||
+ | kernel -- sleep; | ||
+ | kernel -- runmem; | ||
+ | sleep -- swap; | ||
+ | swap -- runswap; | ||
+ | runswap -- new; | ||
+ | runswap -- runmem;n | ||
+ | new -- runmem; | ||
+ | sleep -- runmem; | ||
+ | } | ||
+ | </graphviz> | ||
+ | |||
+ | |} | ||
+ | |||
+ | = Installation = | ||
+ | If you'd like to run your own service you need a python 3 environment includin pip3. The software has been tested on Ubuntu 18.04 and Mac OS 13.6 using macports. | ||
+ | <source lang='bash'> | ||
+ | git clone https://github.com/BITPlan/diagrams | ||
+ | cd diagrams | ||
+ | scripts/install | ||
+ | </source> | ||
+ | |||
+ | = Running = | ||
+ | == Usage == | ||
+ | <source lang='bash'> | ||
+ | python3 dgs/webserver.py -h | ||
+ | usage: webserver.py [-h] [--debug] [--port PORT] [--host HOST] | ||
+ | |||
+ | Diagrams rendering webservice | ||
+ | |||
+ | optional arguments: | ||
+ | -h, --help show this help message and exit | ||
+ | --debug run in debug mode | ||
+ | --port PORT the port to use | ||
+ | --host HOST the host to serve for | ||
+ | </source> | ||
+ | == starting webservice == | ||
+ | <source lang='bash'> | ||
+ | export PYTHONPATH="." | ||
+ | python3 dgs/webserver.py | ||
+ | </source> | ||
+ | By default the webservice will be available on port 5003. | ||
+ | == trying == | ||
+ | You might want to adapt the url "https://diagrams.bitplan.com" to your webserver's url e.g. "http://localhost:5003" | ||
+ | <source lang='bash' highlight='1'> | ||
+ | curl -X POST -F 'generator=plantuml' -F source='vrsion' https://diagrams.bitplan.com/render | ||
+ | </source> | ||
+ | should return | ||
+ | <source lang='json'> | ||
+ | { | ||
+ | "diagrams": { | ||
+ | "png": { | ||
+ | "url": "https://diagrams.bitplan.com/render/png/0x97cd3329.png" | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | [https://diagrams.bitplan.com/render/png/0x97cd3329.png <nowiki>https://diagrams.bitplan.com/render/png/0x97cd3329.png</nowiki>] containing: | ||
+ | https://diagrams.bitplan.com/render/png/0x97cd3329.png | ||
+ | |||
+ | = MediaWiki Diagrams extension = | ||
+ | The webservice can be used as endpoint for the [https://www.mediawiki.org/wiki/Extension:Diagrams the MediaWiki diagrams extension] | ||
+ | {{Extension | ||
+ | |name=Diagrams | ||
+ | |url=https://www.mediawiki.org/wiki/Extension:Diagrams | ||
+ | |purpose=Replaces deprecated | ||
+ | https://www.mediawiki.org/wiki/Extension:GraphViz and | ||
+ | https://www.mediawiki.org/wiki/Extension:PlantUML | ||
+ | extensions | ||
+ | |since=2019/12/12 | ||
+ | |storemode=property | ||
+ | }} | ||
+ | |||
+ | = Installation = | ||
+ | <source lang='bash'> | ||
+ | git clone https://github.com/samwilson/diagrams-extension Diagrams | ||
+ | wfLoadExtension( 'Diagrams' ); | ||
+ | // The URL at which you installed the Diagrams Service. | ||
+ | $wgDiagramsServiceUrl = 'http://diagrams.bitplan.com'; | ||
+ | </source> | ||
+ | |||
+ | == Install the extension == | ||
+ | <source lang='bash'> | ||
+ | cd extensions | ||
+ | git clone https://github.com/samwilson/diagrams-extension.git Diagrams | ||
+ | Cloning into 'Diagrams'... | ||
+ | </source> | ||
+ | == Loading extension == | ||
+ | in LocalSettings.php add | ||
+ | <source lang='php'> | ||
+ | $wgDiagramsServiceUrl ='https://diagrams.bitplan.com'; | ||
+ | wfLoadExtension( 'Diagrams' ); | ||
+ | </source> | ||
+ | replacing the $wgDiagramsServiceUrl with your own webservice to improve performance | ||
+ | |||
+ | == MediaWiki 1.33.4 workaround == | ||
+ | === Hooks.php === | ||
+ | <source lang='php> | ||
+ | <?php | ||
+ | namespace MediaWiki\Extension\Diagrams; | ||
+ | |||
+ | use Html; | ||
+ | use Http; | ||
+ | use MediaWiki\MediaWikiServices; | ||
+ | use Parser; | ||
+ | use MediaWiki\Logger\LoggerFactory; | ||
+ | |||
+ | |||
+ | class Hooks { | ||
+ | |||
+ | /** | ||
+ | * @see https://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit | ||
+ | * @param Parser $parser | ||
+ | */ | ||
+ | public static function onParserFirstCallInit( Parser $parser ) { | ||
+ | foreach ( [ 'graphviz', 'mscgen', 'uml' ] as $tag ) { | ||
+ | $parser->setHook( $tag, function ( string $input, array $args) use ( $tag ) { | ||
+ | $logger = LoggerFactory::getInstance( 'Diagrams' ); | ||
+ | $logger->debug("tag=".$tag); | ||
+ | $generator=$tag; | ||
+ | switch ($tag) { | ||
+ | case 'graphviz': $format='cmapx';break; | ||
+ | case 'mscgen' : $format='ismap';break; | ||
+ | case 'uml': $format='png';$generator='plantuml'; break; | ||
+ | default: $format="png"; | ||
+ | } | ||
+ | if (isset($args["format"])) { | ||
+ | $format=$args["format"]; | ||
+ | $logger->debug("log format=".$format); | ||
+ | } | ||
+ | // Make sure there's something to render. | ||
+ | $input = trim( $input ); | ||
+ | if ( $input === '' ) { | ||
+ | return ''; | ||
+ | } | ||
+ | return static::render( $generator, $input, $format ); | ||
+ | } ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Get HTML for an error message. | ||
+ | * @param string $error Error message. May contain HTML. | ||
+ | * @return string | ||
+ | */ | ||
+ | protected static function formatError( $error ) { | ||
+ | return Html::rawElement( 'span', [ 'class' => 'ext-diagrams error' ], $error ); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The main rendering method, handling all types. | ||
+ | * @param string $generator | ||
+ | * @param string $input | ||
+ | * @param string $format | ||
+ | * @return string | ||
+ | */ | ||
+ | protected static function render( $generator, $input, $format) { | ||
+ | $baseUrl = MediaWikiServices::getInstance()->getMainConfig()->get( 'DiagramsServiceUrl' ); | ||
+ | $url = trim( $baseUrl, '/' ) . '/render'; | ||
+ | # log debug information | ||
+ | $logger = LoggerFactory::getInstance( 'Diagrams' ); | ||
+ | $logger->debug("url=".$url); | ||
+ | $logger->debug("generator=".$generator); | ||
+ | $logger->debug("format=".$format); | ||
+ | $params = [ | ||
+ | 'postData' => http_build_query( [ | ||
+ | 'generator' => $generator, | ||
+ | 'types' => $format, | ||
+ | 'source' => $input, | ||
+ | ] ), | ||
+ | ]; | ||
+ | $result = Http::request( 'POST', $url, $params, __METHOD__ ); | ||
+ | if ( $result === false ) { | ||
+ | return static::formatError( wfMessage( 'diagrams-error-no-response' ) ); | ||
+ | } | ||
+ | $response = json_decode( $result ); | ||
+ | if ( isset( $response->error ) ) { | ||
+ | $error = wfMessage( 'diagrams-error-returned-' . $response->error ); | ||
+ | if ( isset( $response->message ) ) { | ||
+ | $error .= Html::element( 'br' ) . $response->message; | ||
+ | } | ||
+ | return static::formatError( $error ); | ||
+ | } | ||
+ | if ( isset( $response->diagrams->cmapx->contents ) ) { | ||
+ | // Image maps in cmapx format. | ||
+ | $imageMap = new ImageMap( $response->diagrams->cmapx->contents ); | ||
+ | if ( $imageMap->hasAreas() ) { | ||
+ | $imgAttrs['usemap'] = '#' . $imageMap->getName(); | ||
+ | } | ||
+ | $out = Html::element( 'img', $imgAttrs ); | ||
+ | if ( $imageMap->hasAreas() ) { | ||
+ | $out .= $imageMap->getMap(); | ||
+ | } | ||
+ | } elseif ( isset( $response->diagrams->ismap->contents ) ) { | ||
+ | // Image maps in imap format. | ||
+ | $imgAttrs['ismap'] = true; | ||
+ | $out = Html::rawElement( | ||
+ | 'a', | ||
+ | [ 'href' => $response->diagrams->ismap->url ], | ||
+ | Html::element( 'img', $imgAttrs ) | ||
+ | ); | ||
+ | } else { | ||
+ | // No image map. - plain format | ||
+ | switch ($format) { | ||
+ | case 'svg': | ||
+ | $objectAttrs= [ 'data' => $response->diagrams->svg->url, type=>'image/svg+xml']; | ||
+ | $out = Html::rawElement( | ||
+ | 'object', | ||
+ | $objectAttrs | ||
+ | ); | ||
+ | break; | ||
+ | default: | ||
+ | $imgAttrs = [ 'src' => $response->diagrams->png->url ]; | ||
+ | $out = Html::element( 'img', $imgAttrs ); | ||
+ | } | ||
+ | } | ||
+ | return Html::rawElement( 'div', [ 'class' => 'ext-diagrams' ], $out ); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
− | = Json API = | + | = MediaWiki Diagrams Extension Json API = |
+ | The communication between [https://www.mediawiki.org/wiki/Extension:Diagrams the MediaWiki diagrams extension] and this webservice | ||
+ | is done with POST requests that expect Json responses. | ||
== Diagrams == | == Diagrams == | ||
Example | Example |
Revision as of 17:57, 24 November 2020
OsProject | |
---|---|
id | diagrams |
state | |
owner | BITPlan |
title | Diagrams rendering service for graphviz, mscgen and plantuml |
url | https://github.com/BITPlan/diagrams |
version | 0.0.1 |
description | |
date | 2020-02-14 |
since | |
until |
Click here to comment see Diagrams
What is it ?
This is a Python based webservice to render diagrams for
Demo
Examples
tool | source | image |
---|---|---|
dot | <graphviz> graph development { Stakeholder -- Requirements; Requirements -- Samplecases; Requirements -- Model; Model -- Code; } </graphviz> |
![]() |
neato | <graphviz renderer='neato'> graph G { run -- intr; intr -- runbl; runbl -- run; run -- kernel; kernel -- zombie; kernel -- sleep; kernel -- runmem; sleep -- swap; swap -- runswap; runswap -- new; runswap -- runmem;n new -- runmem; sleep -- runmem; } </graphviz> |
![]() |
Installation
If you'd like to run your own service you need a python 3 environment includin pip3. The software has been tested on Ubuntu 18.04 and Mac OS 13.6 using macports.
git clone https://github.com/BITPlan/diagrams
cd diagrams
scripts/install
Running
Usage
python3 dgs/webserver.py -h
usage: webserver.py [-h] [--debug] [--port PORT] [--host HOST]
Diagrams rendering webservice
optional arguments:
-h, --help show this help message and exit
--debug run in debug mode
--port PORT the port to use
--host HOST the host to serve for
starting webservice
export PYTHONPATH="."
python3 dgs/webserver.py
By default the webservice will be available on port 5003.
trying
You might want to adapt the url "https://diagrams.bitplan.com" to your webserver's url e.g. "http://localhost:5003"
curl -X POST -F 'generator=plantuml' -F source='vrsion' https://diagrams.bitplan.com/render
should return
{
"diagrams": {
"png": {
"url": "https://diagrams.bitplan.com/render/png/0x97cd3329.png"
}
}
https://diagrams.bitplan.com/render/png/0x97cd3329.png containing:
MediaWiki Diagrams extension
The webservice can be used as endpoint for the the MediaWiki diagrams extension
Extension | |
---|---|
name | Diagrams |
url | https://www.mediawiki.org/wiki/Extension:Diagrams |
purpose | Replaces deprecated
https://www.mediawiki.org/wiki/Extension:GraphViz and https://www.mediawiki.org/wiki/Extension:PlantUML extensions |
since | 2019/12/12 |
wiki |
Installation
git clone https://github.com/samwilson/diagrams-extension Diagrams
wfLoadExtension( 'Diagrams' );
// The URL at which you installed the Diagrams Service.
$wgDiagramsServiceUrl = 'http://diagrams.bitplan.com';
Install the extension
cd extensions
git clone https://github.com/samwilson/diagrams-extension.git Diagrams
Cloning into 'Diagrams'...
Loading extension
in LocalSettings.php add
$wgDiagramsServiceUrl ='https://diagrams.bitplan.com';
wfLoadExtension( 'Diagrams' );
replacing the $wgDiagramsServiceUrl with your own webservice to improve performance
MediaWiki 1.33.4 workaround
Hooks.php
<?php
namespace MediaWiki\Extension\Diagrams;
use Html;
use Http;
use MediaWiki\MediaWikiServices;
use Parser;
use MediaWiki\Logger\LoggerFactory;
class Hooks {
/**
* @see https://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit
* @param Parser $parser
*/
public static function onParserFirstCallInit( Parser $parser ) {
foreach ( [ 'graphviz', 'mscgen', 'uml' ] as $tag ) {
$parser->setHook( $tag, function ( string $input, array $args) use ( $tag ) {
$logger = LoggerFactory::getInstance( 'Diagrams' );
$logger->debug("tag=".$tag);
$generator=$tag;
switch ($tag) {
case 'graphviz': $format='cmapx';break;
case 'mscgen' : $format='ismap';break;
case 'uml': $format='png';$generator='plantuml'; break;
default: $format="png";
}
if (isset($args["format"])) {
$format=$args["format"];
$logger->debug("log format=".$format);
}
// Make sure there's something to render.
$input = trim( $input );
if ( $input === '' ) {
return '';
}
return static::render( $generator, $input, $format );
} );
}
}
/**
* Get HTML for an error message.
* @param string $error Error message. May contain HTML.
* @return string
*/
protected static function formatError( $error ) {
return Html::rawElement( 'span', [ 'class' => 'ext-diagrams error' ], $error );
}
/**
* The main rendering method, handling all types.
* @param string $generator
* @param string $input
* @param string $format
* @return string
*/
protected static function render( $generator, $input, $format) {
$baseUrl = MediaWikiServices::getInstance()->getMainConfig()->get( 'DiagramsServiceUrl' );
$url = trim( $baseUrl, '/' ) . '/render';
# log debug information
$logger = LoggerFactory::getInstance( 'Diagrams' );
$logger->debug("url=".$url);
$logger->debug("generator=".$generator);
$logger->debug("format=".$format);
$params = [
'postData' => http_build_query( [
'generator' => $generator,
'types' => $format,
'source' => $input,
] ),
];
$result = Http::request( 'POST', $url, $params, __METHOD__ );
if ( $result === false ) {
return static::formatError( wfMessage( 'diagrams-error-no-response' ) );
}
$response = json_decode( $result );
if ( isset( $response->error ) ) {
$error = wfMessage( 'diagrams-error-returned-' . $response->error );
if ( isset( $response->message ) ) {
$error .= Html::element( 'br' ) . $response->message;
}
return static::formatError( $error );
}
if ( isset( $response->diagrams->cmapx->contents ) ) {
// Image maps in cmapx format.
$imageMap = new ImageMap( $response->diagrams->cmapx->contents );
if ( $imageMap->hasAreas() ) {
$imgAttrs['usemap'] = '#' . $imageMap->getName();
}
$out = Html::element( 'img', $imgAttrs );
if ( $imageMap->hasAreas() ) {
$out .= $imageMap->getMap();
}
} elseif ( isset( $response->diagrams->ismap->contents ) ) {
// Image maps in imap format.
$imgAttrs['ismap'] = true;
$out = Html::rawElement(
'a',
[ 'href' => $response->diagrams->ismap->url ],
Html::element( 'img', $imgAttrs )
);
} else {
// No image map. - plain format
switch ($format) {
case 'svg':
$objectAttrs= [ 'data' => $response->diagrams->svg->url, type=>'image/svg+xml'];
$out = Html::rawElement(
'object',
$objectAttrs
);
break;
default:
$imgAttrs = [ 'src' => $response->diagrams->png->url ];
$out = Html::element( 'img', $imgAttrs );
}
}
return Html::rawElement( 'div', [ 'class' => 'ext-diagrams' ], $out );
}
}
MediaWiki Diagrams Extension Json API
The communication between the MediaWiki diagrams extension and this webservice is done with POST requests that expect Json responses.
Diagrams
Example
{
"diagrams": {
"png": {
"url": "http://diagrams.bitplan.com/render/png/0xb00d69ad"
}
}
}
Errors
Example
{
"error": "service not ready",
"message": "not implemented yet"
}