Diagrams: Difference between revisions

From BITPlan Wiki
Jump to navigation Jump to search
No edit summary
 
(40 intermediate revisions by the same user not shown)
Line 2: Line 2:
|id=diagrams
|id=diagrams
|owner=BITPlan
|owner=BITPlan
|title=Diagrams rendering service for graphviz, mscgen and plantuml
|state=active
|title=online-diagrams
|description=online diagrams rendering service for graphviz, mscgen and plantuml
|url=https://github.com/BITPlan/diagrams
|url=https://github.com/BITPlan/diagrams
|date=2020-02-14
|date=2023-10-28
|version=0.0.1}}
|since=2020-02-14
|version=0.1.0
}}
{{:Diagrams/Links}}
{{:Diagrams/Links}}
= 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 =
{| class="wikitable sortable"
|-
! tool !! source !! image
|-
| dot
| <pre><graphviz>
graph development {
  Stakeholder -- Requirements;
  Requirements -- Samplecases;
  Requirements -- Model;
  Model -- Code;
}
</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='version' 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

Latest revision as of 10:44, 28 October 2023

OsProject
id  diagrams
state  active
owner  BITPlan
title  online-diagrams
url  https://github.com/BITPlan/diagrams
version  0.1.0
description  online diagrams rendering service for graphviz, mscgen and plantuml
date  2023-10-28
since  2020-02-14
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='version' 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: https://diagrams.bitplan.com/render/png/0x97cd3329.png

MediaWiki Diagrams extension

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

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

http://diagrams.bitplan.com/render/png/0xb00d69ad.png

Errors

Example

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

Links