テキストベースで手軽にUML図を描画できるPlantUMLやmermaid。
astah*ユーザーEvan Chenさんが、astah*で描いた図をPlantUMLやmermaid.js用にテキスト変換するスクリプトを書いてくださいました。astah*で描いた図の共有オプション等として、どうぞご活用ください。
現在変換に対応している図種は、シーケンス図とフローチャートです。
スクリプト概要:Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-
スクリプト:
To PlantUML:シーケンス図
To mermaid:シーケンス図 / フローチャート
使い方 (例:シーケンス図)
- astah*でシーケンス図を描きます
- [ツール] – [スクリプトエディタ]を選択して[スクリプトエディタ]ウィンドウを開きます。
(astah* 7.2をご利用の場合は、[スクリプトエディタ]が同梱されているため、当メニューがあります。
7.1以前をご利用の方は、[スクリプトエディタ]プラグインをインストールしてください)
- ウィンドウ上部に、mermaid.js用テキスト変換スクリプトを貼り付けます。三角のボタンを押します。
- ウィンドウ下部にテキストが出力されました。
- これをコピーして、mermaid.js側のエディタに貼り付けると、mermaid.js側で図が表示されます。
PlantUMLに貼り付けた場合は、こうなります。
スクリプト
シーケンス図をPlantUML用に変換
// This script convert Astah SequenceDiagram to plantuml fomat text // Author: Chen Zhi // E-mail: cz_666@qq.com // License: APACHE V2.0 (see license file) var ISequenceDiagram = Java.type('com.change_vision.jude.api.inf.model.ISequenceDiagram'); var ILifeline = Java.type('com.change_vision.jude.api.inf.model.ILifeline'); var IMessage = Java.type('com.change_vision.jude.api.inf.model.IMessage'); var HashMap = Java.type('java.util.HashMap'); run(); function run() { var diagramViewManager = astah.getViewManager().getDiagramViewManager(); var diagram = diagramViewManager.getCurrentDiagram(); if (!(diagram instanceof ISequenceDiagram)) { print('Open a ISequenceDiagram and run again.'); return; } var presentations = diagram.getPresentations(); var lifelinePresentations = getLifelinePresentations(presentations); var lifelineNames = getLifelineNames(lifelinePresentations); var messagePresentations = getMassagePresentations(presentations); print('@startuml'); printLifeline(lifelinePresentations, lifelineNames); printMessages(messagePresentations, lifelineNames); print('@enduml'); } function getLifelinePresentations(presentations) { var lifelinePresentations = new Array(); for (var i in presentations) { var presentation = presentations[i]; if (presentation.getModel() instanceof ILifeline) { lifelinePresentations[i] = presentation; } } lifelinePresentations.sort(orderOfLifelinePosition); return lifelinePresentations; } function orderOfLifelinePosition(a, b) { return a.getLocation().getX() - b.getLocation().getX(); } function getLifelineNames(lifelinePresentations) { var lifelineNames = new HashMap(); for (var i in lifelinePresentations) { var lifelineP = lifelinePresentations[i]; if (lifelineP == undefined) { continue; } var lifeline = lifelineP.getModel(); if (lifeline.getBase() != null) { lifelineNames.put(lifeline, lifeline.getName() + "_" + lifeline.getBase().getName()); } else { lifelineNames.put(lifeline, lifeline.getName()); } } return lifelineNames; } function printLifeline(lifelinePresentations, lifelineNames) { for (var i in lifelinePresentations) { var lifelineP = lifelinePresentations[i]; if (lifelineP == undefined) { continue; } var lifeline = lifelineP.getModel(); print("participant " + lifelineNames.get(lifeline)); } } function getMassagePresentations(presentations) { var messagePresentations = new Array(); for (var i in presentations) { var presentation = presentations[i]; if (presentation.getModel() instanceof IMessage) { messagePresentations[i] = presentation; } } messagePresentations.sort(orderOfMessagePosition); return messagePresentations; } function orderOfMessagePosition(a, b) { return a.getPoints()[0].getY() - b.getPoints()[0].getY(); } function printMessages(messagePresentations, lifelineNames) { for (var i in messagePresentations) { var messageP = messagePresentations[i]; if (messageP == undefined) { continue; } var message = messageP.getModel(); var sourceName = lifelineNames.get(message.getSource()); var targetName = lifelineNames.get(message.getTarget()); print(sourceName + getArrow(message) + targetName + ':' + getText(message)); } } function getArrow(message) { if (message.isReturnMessage()) { return " -->> "; } if (message.isAsynchronous()) { return " ->> "; } return " -> "; } function getText(message) { var index = message.getIndex(); if (message.isReturnMessage()) { index = "reply"; } var messageName = message.getName(); if (messageName == null) { messageName = ""; } return index + '.' + messageName; }
シーケンス図をmermaid用に変換
// This script convert Astah SequenceDiagram to mermaid fomat text // Author: Chen Zhi // E-mail: cz_666@qq.com // License: APACHE V2.0 (see license file) var ISequenceDiagram = Java.type('com.change_vision.jude.api.inf.model.ISequenceDiagram'); var ArrayList = Java.type('java.util.ArrayList'); var Arrays = Java.type('java.util.Arrays'); var Comparator = Java.type('java.util.Comparator'); var Collections = Java.type('java.util.Collections'); var HashMap = Java.type('java.util.HashMap'); var INDENT = ' '; run(); function run() { var diagramViewManager = astah.getViewManager().getDiagramViewManager(); var diagram = diagramViewManager.getCurrentDiagram(); if (!(diagram instanceof ISequenceDiagram)) { print('Open a ISequenceDiagram and run again.'); return; } print(diagram + ' Sequence'); print('```mermaid'); print('sequenceDiagram;'); var lifelinePresentations = getLifelinePresentations(diagram); var lifelineNames = getLifelineNames(lifelinePresentations); printLifelines(lifelinePresentations, lifelineNames); var messagePresentations = getMessagePresentations(diagram); printMessages(messagePresentations, lifelineNames); print('```'); } function getLifelinePresentations(diagram) { var presentations = diagram.getPresentations(); var interaction = diagram.getInteraction(); var lifelines = interaction.getLifelines(); var lifelinePresentations = new ArrayList(); for (var i in presentations) { var presentation = presentations[i]; if (Arrays.asList(lifelines).contains(presentation.getModel())) { lifelinePresentations.add(presentation); } } Collections.sort(lifelinePresentations, new Comparator() { compare: function ( a, b ) { return a.getLocation().getX() - b.getLocation().getX(); } }); return lifelinePresentations; } function getLifelineNames(lifelinePresentations) { var lifelineNames = new HashMap(); for (var i in lifelinePresentations) { var lifeline = lifelinePresentations[i].getModel(); if (lifeline.getBase() != null) { lifelineNames.put(lifeline, lifeline.getName() + '_' + lifeline.getBase()); } else { lifelineNames.put(lifeline, lifeline.getName()); } } return lifelineNames; } function printLifelines(lifelinePresentations, lifelineNames) { for (var i in lifelinePresentations) { var lifeline = lifelinePresentations[i].getModel(); print(INDENT + 'participant ' + lifelineNames.get(lifeline) + ';'); } } function getMessagePresentations(diagram) { var interaction = diagram.getInteraction(); var msgs = interaction.getMessages(); var messagePresentations = new ArrayList(); var presentations = diagram.getPresentations(); for (var i in presentations) { var presentation = presentations[i]; if (Arrays.asList(msgs).contains(presentation.getModel())) { messagePresentations.add(presentation); } } Collections.sort(messagePresentations, new Comparator() { compare: function ( a, b ) { return a.getPoints()[0].getY() - b.getPoints()[0].getY(); } }); return messagePresentations; } function printMessages(messagePresentations, lifelineNames) { for (var i in messagePresentations) { var presentation = messagePresentations[i]; var model = presentation.getModel(); var source = model.getSource(); var target = model.getTarget(); print(INDENT + lifelineNames.get(source) + getArrowString(model) + lifelineNames.get(target) + ':' + getIndexString(model) + '.' + model.getName()); } } function getIndexString(model) { if (model.isReturnMessage()) { return 'reply'; } return model.getIndex(); } function getArrowString(model) { if (model.isReturnMessage()) { return '-->>'; } if (model.isAsynchronous()) { return '-x'; } return '->>'; }
フローチャートをmermaid用に変換
// This script convert Astah flowchart to mermaid fomat text // Author: Chen Zhi // E-mail: cz_666@qq.com // License: APACHE V2.0 (see license file) var IActivityDiagram = Java.type('com.change_vision.jude.api.inf.model.IActivityDiagram'); var IControlNode = Java.type('com.change_vision.jude.api.inf.model.IControlNode'); var HashMap = Java.type('java.util.HashMap'); var ID_PREFIX = 'A'; var REPLACEMENT_CHAR = '?'; var INDENT = ' '; run(); function run() { var diagramViewManager = astah.getViewManager().getDiagramViewManager(); var diagram = diagramViewManager.getCurrentDiagram(); if (!(diagram instanceof IActivityDiagram)) { print('Open a flowchart and run again.'); return; } if (!(diagram.isFlowChart())) { print('Open a flowchart and run again.'); return; } var activity = diagram.getActivity(); var activityNodes = activity.getActivityNodes(); var activityNodeIds = getActivityNodeIds(activityNodes); var flows = activity.getFlows(); print(diagram + ' Flowchart'); print('```mermaid'); print('graph TB'); printObjectDefine(activityNodes, activityNodeIds); printFlowchartLogic(flows, activityNodeIds); print('```'); } function getActivityNodeIds(activityNodes) { var activityNodeIds = new HashMap(); for (var i in activityNodes) { var nodeId = ID_PREFIX + i; var node = activityNodes[i]; activityNodeIds.put(node, nodeId); } return activityNodeIds; } function printObjectDefine(activityNodes, activityNodeIds) { for (var i in activityNodes) { var node = activityNodes[i]; var nodeId = activityNodeIds.get(node); if (isRhombus(node)) { print(INDENT + nodeId + '{' + replaceUnavailableCharacters(node.getName()) + '}'); continue; } if (isRectangle(node)) { print(INDENT + nodeId + '[' + replaceUnavailableCharacters(node.getName()) + ']'); continue; } print(INDENT + nodeId + '(' + replaceUnavailableCharacters(node.getName()) + ')'); } } function replaceUnavailableCharacters(string) { var newString = string.replace(/\n/g, ' '); newString = newString.replace(/\(/g, REPLACEMENT_CHAR); newString = newString.replace(/\)/g, REPLACEMENT_CHAR); newString = newString.replace(/\[/g, REPLACEMENT_CHAR); newString = newString.replace(/\]/g, REPLACEMENT_CHAR); newString = newString.replace(/\{/g, REPLACEMENT_CHAR); newString = newString.replace(/\}/g, REPLACEMENT_CHAR); newString = newString.replace(/\;/g, REPLACEMENT_CHAR); newString = newString.replace(/\|/g, REPLACEMENT_CHAR); newString = newString.replace(/E/g, REPLACEMENT_CHAR); return newString; } function printFlowchartLogic(flows, activityNodeIds) { for (var i in flows) { var flow = flows[i]; var sourceId = activityNodeIds.get(flow.getSource()); if (sourceId == null) { continue; } var targetId = activityNodeIds.get(flow.getTarget()); if (targetId == null) { continue; } if (flow.getGuard() != "") { print(INDENT + sourceId + "-->|" + replaceUnavailableCharacters(flow.getGuard()) + "| " + targetId); continue; } print(INDENT + sourceId + "-->" + targetId); } } function isRhombus(node) { if (node instanceof IControlNode && node.isDecisionMergeNode()) { return true; } var stereotypes = node.getStereotypes(); return stereotypes.length > 0 && 'judgement'.equals(stereotypes[0]); } function isRectangle(node) { var stereotypes = node.getStereotypes(); return stereotypes.length > 0 && 'flow_process'.equals(stereotypes[0]); }
「astah*で描いた図をPlantUMLやmermaid用に変換」への2件のフィードバック