Difference between revisions of "Diagrams"

From BITPlan Wiki
Jump to navigation Jump to search
Line 118: Line 118:
 
in LocalSettings.php add
 
in LocalSettings.php add
 
<source lang='php'>
 
<source lang='php'>
$wgDiagramsServiceUrl ='http://diagrams.bitplan.com';
+
$wgDiagramsServiceUrl ='https://diagrams.bitplan.com';
 
wfLoadExtension( 'Diagrams' );
 
wfLoadExtension( 'Diagrams' );
 
</source>
 
</source>
 
replacing the $wgDiagramsServiceUrl with your own webservice to improve performance
 
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);
 +
if (isset($args["format"])) {
 +
$format=$args["format"];
 +
$logger->debug("log format=".$format);
 +
} else {
 +
$format="png";
 +
}
 +
 +
// Make sure there's something to render.
 +
$input = trim( $input );
 +
if ( $input === '' ) {
 +
return '';
 +
}
 +
if ( $tag === 'graphviz' ) {
 +
// GraphViz.
 +
return static::render( $tag, $input, 'cmapx' );
 +
} elseif ( $tag === 'mscgen' ) {
 +
// Mscgen.
 +
return static::render( $tag, $input, 'ismap' );
 +
} else {
 +
// PlantUML.
 +
return static::render( 'plantuml', $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 = null ) {
 +
$baseUrl = MediaWikiServices::getInstance()->getMainConfig()->get( 'DiagramsServiceUrl' );
 +
$url = trim( $baseUrl, '/' ) . '/render';
 +
$logger = LoggerFactory::getInstance( 'Diagrams' );
 +
$logger->debug("url=".$url);
 +
$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 =

Revision as of 08:34, 4 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.

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);
			if (isset($args["format"])) {
				$format=$args["format"];
				$logger->debug("log format=".$format);
			} else {
				$format="png";
			}
				
				// Make sure there's something to render.
				$input = trim( $input );
				if ( $input === '' ) {
					return '';
				}
				if ( $tag === 'graphviz' ) {
					// GraphViz.
					return static::render( $tag, $input, 'cmapx' );
				} elseif ( $tag === 'mscgen' ) {
					// Mscgen.
					return static::render( $tag, $input, 'ismap' );
				} else {
					// PlantUML.
					return static::render( 'plantuml', $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 = null ) {
		$baseUrl = MediaWikiServices::getInstance()->getMainConfig()->get( 'DiagramsServiceUrl' );
		$url = trim( $baseUrl, '/' ) . '/render';
		$logger = LoggerFactory::getInstance( 'Diagrams' );
		$logger->debug("url=".$url);
		$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