Diagrams

From BITPlan Wiki
Jump to navigation Jump to search
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 {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

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

0xb00d69ad.png

Errors

Example

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

Links