Difference between revisions of "Diagrams"

From BITPlan Wiki
Jump to navigation Jump to search
 
(19 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 ? =
Line 83: Line 87:
 
git clone https://github.com/BITPlan/diagrams
 
git clone https://github.com/BITPlan/diagrams
 
cd diagrams
 
cd diagrams
./install
+
scripts/install
 
</source>
 
</source>
 +
 
= Running =
 
= Running =
 
== Usage ==
 
== Usage ==
Line 105: Line 110:
 
</source>
 
</source>
 
By default the webservice will be available on port 5003.
 
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>
  
 
= MediaWiki Diagrams Extension Json API =
 
= MediaWiki Diagrams Extension Json API =

Latest revision as of 11: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: 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"
          }
       }
    }

0xb00d69ad.png

Errors

Example

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

Links