Difference between revisions of "Diagrams"

From BITPlan Wiki
Jump to navigation Jump to search
(33 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
# graphviz
+
* [[File:GraphVizLogo.png|link=https://www.graphviz.org/|graphviz]][https://www.graphviz.org graphviz]
# mscgen
+
* [[File:Msc-sig.png|link=http://www.mcternan.me.uk/mscgen/|mscgen]][http://www.mcternan.me.uk/mscgen mscgen]
# plantuml
+
* [[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 =
== dot ==
+
{| class="wikitable sortable"
<graphviz>
+
|-
 +
! tool !! source !! image
 +
|-
 +
| dot  
 +
| <pre><graphviz>
 +
graph development {
 +
  Stakeholder -- Requirements;
 +
  Requirements -- Samplecases;
 +
  Requirements -- Model;
 +
  Model -- Code;
 +
}
 +
</graphviz>
 +
</pre>
 +
| <graphviz>
 
graph development {  
 
graph development {  
 
   Stakeholder -- Requirements;  
 
   Stakeholder -- Requirements;  
Line 24: Line 38:
 
}
 
}
 
</graphviz>
 
</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]
 +
 +
== 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 07:01, 5 September 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

https://diagrams.bitplan.com

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: 0x97cd3329.png

MediaWiki Diagrams extension

The webservice can be used as endpoint for the the MediaWiki diagrams extension

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"
          }
       }
    }

0xb00d69ad.png

Errors

Example

{ 
  "error": "service not ready",
  "message": "not implemented yet"
}

Links