From b11e65ebb403c262dff22ef0ca18ee4a1aa1d453 Mon Sep 17 00:00:00 2001 From: lujian Date: Thu, 10 Jan 2019 18:19:50 +0800 Subject: [PATCH 1/2] gh files --- css/graphviz.svg.css | 42 ++ demo.svg | 1270 +++++++++++++++++++++++++++++++++++++ index.html | 70 ++ js/jquery.graphviz.svg.js | 534 ++++++++++++++++ usage1.png | Bin 0 -> 10998 bytes usage2.png | Bin 0 -> 26947 bytes 6 files changed, 1916 insertions(+) create mode 100644 css/graphviz.svg.css create mode 100644 demo.svg create mode 100644 index.html create mode 100644 js/jquery.graphviz.svg.js create mode 100644 usage1.png create mode 100644 usage2.png diff --git a/css/graphviz.svg.css b/css/graphviz.svg.css new file mode 100644 index 0000000..ba4da2e --- /dev/null +++ b/css/graphviz.svg.css @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015 Mountainstorm + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* this element needs tooltip positioning to work */ +.graphviz-svg { + position: relative; +} + +/* stop tooltips wrapping */ +.graphviz-svg .tooltip-inner { + white-space: nowrap; +} + +/* stop people selecting text on nodes */ +.graphviz-svg text { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default; +} diff --git a/demo.svg b/demo.svg new file mode 100644 index 0000000..4815892 --- /dev/null +++ b/demo.svg @@ -0,0 +1,1270 @@ + + +sampleDigraph + + +RunnableScheduledFuture + + +RunnableScheduledFuture + + + + +RunnableFuture<V> + + +RunnableFuture<V> + + + + +RunnableScheduledFuture->RunnableFuture<V> + + + + +ConcurrentLinkedQueue + + +ConcurrentLinkedQueue + + + + +Queue + + +Queue + + + + +ConcurrentLinkedQueue->Queue + + + + +Serializable + + +Serializable + + + + +ConcurrentLinkedQueue->Serializable + + + + +AbstractQueue<E> + + +AbstractQueue<E> + + + + +ConcurrentLinkedQueue->AbstractQueue<E> + + + + +LockSupport + + +LockSupport + + + + +ReadWriteLock + + +ReadWriteLock + + + + +AtomicInteger + + +AtomicInteger + + + + +AtomicInteger->Serializable + + + + +Number + + +Number + + + + +AtomicInteger->Number + + + + +CopyOnWriteArrayList + + +CopyOnWriteArrayList + + + + +CopyOnWriteArrayList->Serializable + + + + +Cloneable + + +Cloneable + + + + +CopyOnWriteArrayList->Cloneable + + + + +RandomAccess + + +RandomAccess + + + + +CopyOnWriteArrayList->RandomAccess + + + + +List + + +List + + + + +CopyOnWriteArrayList->List + + + + +RunnableFuture + + +RunnableFuture + + + + +Runnable + + +Runnable + + + + +RunnableFuture->Runnable + + + + +BrokenBarrierException + + +BrokenBarrierException + + + + +Exception + + +Exception + + + + +BrokenBarrierException->Exception + + + + +AbstractExecutorService + + +AbstractExecutorService + + + + +ExecutorService + + +ExecutorService + + + + +AbstractExecutorService->ExecutorService + + + + +Executor + + +Executor + + + + +ExecutorService->Executor + + + + +LinkedBlockingQueue + + +LinkedBlockingQueue + + + + +LinkedBlockingQueue->Serializable + + + + +LinkedBlockingQueue->AbstractQueue<E> + + + + +BlockingQueue + + +BlockingQueue + + + + +LinkedBlockingQueue->BlockingQueue + + + + +Queue<E> + + +Queue<E> + + + + +BlockingQueue->Queue<E> + + + + +ScheduledFuture + + +ScheduledFuture + + + + +Delayed + + +Delayed + + + + +ScheduledFuture->Delayed + + + + +Comparable<Delayed> + + +Comparable<Delayed> + + + + +Delayed->Comparable<Delayed> + + + + +ConcurrentSkipListMap + + +ConcurrentSkipListMap + + + + +ConcurrentSkipListMap->Serializable + + + + +ConcurrentSkipListMap->Cloneable + + + + +AbstractMap<K,V> + + +AbstractMap<K,V> + + + + +ConcurrentSkipListMap->AbstractMap<K,V> + + + + +ConcurrentNavigableMap + + +ConcurrentNavigableMap + + + + +ConcurrentSkipListMap->ConcurrentNavigableMap + + + + +ConcurrentMap<K,V> + + +ConcurrentMap<K,V> + + + + +ConcurrentNavigableMap->ConcurrentMap<K,V> + + + + +AbstractOwnableSynchronizer + + +AbstractOwnableSynchronizer + + + + +AbstractOwnableSynchronizer->Serializable + + + + +AtomicReferenceFieldUpdater + + +AtomicReferenceFieldUpdater + + + + +PriorityBlockingQueue + + +PriorityBlockingQueue + + + + +PriorityBlockingQueue->Serializable + + + + +PriorityBlockingQueue->AbstractQueue<E> + + + + +PriorityBlockingQueue->BlockingQueue + + + + +Phaser + + +Phaser + + + + +RejectedExecutionHandler + + +RejectedExecutionHandler + + + + +AtomicLong + + +AtomicLong + + + + +AtomicLong->Serializable + + + + +AtomicLong->Number + + + + +Condition + + +Condition + + + + +ThreadPoolExecutor + + +ThreadPoolExecutor + + + + +ThreadPoolExecutor->AbstractExecutorService + + + + +RecursiveAction + + +RecursiveAction + + + + +ForkJoinTask<Void> + + +ForkJoinTask<Void> + + + + +RecursiveAction->ForkJoinTask<Void> + + + + +AtomicReferenceArray + + +AtomicReferenceArray + + + + +AtomicReferenceArray->Serializable + + + + +Future + + +Future + + + + +RecursiveTask + + +RecursiveTask + + + + +ForkJoinTask<V> + + +ForkJoinTask<V> + + + + +RecursiveTask->ForkJoinTask<V> + + + + +SynchronousQueue + + +SynchronousQueue + + + + +SynchronousQueue->Serializable + + + + +SynchronousQueue->AbstractQueue<E> + + + + +SynchronousQueue->BlockingQueue + + + + +AtomicMarkableReference + + +AtomicMarkableReference + + + + +RejectedExecutionException + + +RejectedExecutionException + + + + +RuntimeException + + +RuntimeException + + + + +RejectedExecutionException->RuntimeException + + + + +ArrayBlockingQueue + + +ArrayBlockingQueue + + + + +ArrayBlockingQueue->Serializable + + + + +ArrayBlockingQueue->AbstractQueue<E> + + + + +ArrayBlockingQueue->BlockingQueue + + + + +AtomicLongArray + + +AtomicLongArray + + + + +AtomicLongArray->Serializable + + + + +AtomicStampedReference + + +AtomicStampedReference + + + + +ConcurrentLinkedDeque + + +ConcurrentLinkedDeque + + + + +ConcurrentLinkedDeque->Serializable + + + + +Deque + + +Deque + + + + +ConcurrentLinkedDeque->Deque + + + + +AbstractCollection<E> + + +AbstractCollection<E> + + + + +ConcurrentLinkedDeque->AbstractCollection<E> + + + + +AtomicLongFieldUpdater + + +AtomicLongFieldUpdater + + + + +ReentrantLock + + +ReentrantLock + + + + +ReentrantLock->Serializable + + + + +Lock + + +Lock + + + + +ReentrantLock->Lock + + + + +CopyOnWriteArraySet + + +CopyOnWriteArraySet + + + + +CopyOnWriteArraySet->Serializable + + + + +AbstractSet<E> + + +AbstractSet<E> + + + + +CopyOnWriteArraySet->AbstractSet<E> + + + + +ReentrantReadWriteLock + + +ReentrantReadWriteLock + + + + +ReentrantReadWriteLock->Serializable + + + + +ReentrantReadWriteLock->ReadWriteLock + + + + +CancellationException + + +CancellationException + + + + +IllegalStateException + + +IllegalStateException + + + + +CancellationException->IllegalStateException + + + + +Exchanger + + +Exchanger + + + + +DelayQueue + + +DelayQueue + + + + +DelayQueue->AbstractQueue<E> + + + + +DelayQueue->BlockingQueue + + + + +ThreadFactory + + +ThreadFactory + + + + +ForkJoinPool + + +ForkJoinPool + + + + +ForkJoinPool->AbstractExecutorService + + + + +ExecutionException + + +ExecutionException + + + + +ExecutionException->Exception + + + + +ExecutorCompletionService + + +ExecutorCompletionService + + + + +CompletionService + + +CompletionService + + + + +ExecutorCompletionService->CompletionService + + + + +BlockingDeque + + +BlockingDeque + + + + +BlockingQueue<E> + + +BlockingQueue<E> + + + + +BlockingDeque->BlockingQueue<E> + + + + +ConcurrentSkipListSet + + +ConcurrentSkipListSet + + + + +ConcurrentSkipListSet->Serializable + + + + +ConcurrentSkipListSet->Cloneable + + + + +ConcurrentSkipListSet->AbstractSet<E> + + + + +NavigableSet + + +NavigableSet + + + + +ConcurrentSkipListSet->NavigableSet + + + + +FutureTask + + +FutureTask + + + + +FutureTask->RunnableFuture + + + + +AbstractQueuedLongSynchronizer + + +AbstractQueuedLongSynchronizer + + + + +AbstractQueuedLongSynchronizer->Serializable + + + + +AbstractQueuedLongSynchronizer->AbstractOwnableSynchronizer + + + + +Executors + + +Executors + + + + +ForkJoinWorkerThread + + +ForkJoinWorkerThread + + + + +Thread + + +Thread + + + + +ForkJoinWorkerThread->Thread + + + + +AtomicReference + + +AtomicReference + + + + +AtomicReference->Serializable + + + + +LinkedBlockingDeque + + +LinkedBlockingDeque + + + + +LinkedBlockingDeque->Serializable + + + + +LinkedBlockingDeque->AbstractQueue<E> + + + + +LinkedBlockingDeque->BlockingDeque + + + + +ThreadLocalRandom + + +ThreadLocalRandom + + + + +Random + + +Random + + + + +ThreadLocalRandom->Random + + + + +CyclicBarrier + + +CyclicBarrier + + + + +ConcurrentMap + + +ConcurrentMap + + + + +Map<K,V> + + +Map<K,V> + + + + +ConcurrentMap->Map<K,V> + + + + +AtomicIntegerArray + + +AtomicIntegerArray + + + + +AtomicIntegerArray->Serializable + + + + +TransferQueue + + +TransferQueue + + + + +TransferQueue->BlockingQueue<E> + + + + +ForkJoinTask + + +ForkJoinTask + + + + +ForkJoinTask->Serializable + + + + +ForkJoinTask->Future + + + + +ScheduledThreadPoolExecutor + + +ScheduledThreadPoolExecutor + + + + +ScheduledThreadPoolExecutor->ThreadPoolExecutor + + + + +ScheduledExecutorService + + +ScheduledExecutorService + + + + +ScheduledThreadPoolExecutor->ScheduledExecutorService + + + + +ScheduledExecutorService->ExecutorService + + + + +AbstractQueuedSynchronizer + + +AbstractQueuedSynchronizer + + + + +AbstractQueuedSynchronizer->Serializable + + + + +AbstractQueuedSynchronizer->AbstractOwnableSynchronizer + + + + +AtomicIntegerFieldUpdater + + +AtomicIntegerFieldUpdater + + + + +AtomicBoolean + + +AtomicBoolean + + + + +AtomicBoolean->Serializable + + + + +TimeoutException + + +TimeoutException + + + + +TimeoutException->Exception + + + + +Callable + + +Callable + + + + +ConcurrentHashMap + + +ConcurrentHashMap + + + + +ConcurrentHashMap->Serializable + + + + +ConcurrentHashMap->AbstractMap<K,V> + + + + +ConcurrentHashMap->ConcurrentMap + + + + +CountDownLatch + + +CountDownLatch + + + + +LinkedTransferQueue + + +LinkedTransferQueue + + + + +LinkedTransferQueue->Serializable + + + + +LinkedTransferQueue->AbstractQueue<E> + + + + +LinkedTransferQueue->TransferQueue + + + + +TimeUnit + + +TimeUnit + + + + +Semaphore + + +Semaphore + + + + +Semaphore->Serializable + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..298b347 --- /dev/null +++ b/index.html @@ -0,0 +1,70 @@ + + + + + + + + + +

Click node to highlight; Shift-scroll to zoom; Esc to unhighlight

+
+ + + + + + + + + diff --git a/js/jquery.graphviz.svg.js b/js/jquery.graphviz.svg.js new file mode 100644 index 0000000..bc800a3 --- /dev/null +++ b/js/jquery.graphviz.svg.js @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2015 Mountainstorm + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + + +function ($) { + 'use strict' + + // Cross Browser starts/endsWith support + // ===================================== + String.prototype.startsWith = function(prefix) { + return this.indexOf(prefix) == 0; + }; + + String.prototype.endsWith = function(suffix) { + return this.indexOf(suffix, this.length - suffix.length) !== -1; + }; + + // GRAPHVIZSVG PUBLIC CLASS DEFINITION + // =================================== + + var GraphvizSvg = function (element, options) { + this.type = null + this.options = null + this.enabled = null + this.$element = null + + this.init('graphviz.svg', element, options) + } + + GraphvizSvg.VERSION = '1.0.1' + + GraphvizSvg.GVPT_2_PX = 32.5 // used to ease removal of extra space + + GraphvizSvg.DEFAULTS = { + url: null, + svg: null, + shrink: '0.125pt', + tooltips: { + init: function ($graph) { + var $a = $(this) + $a.tooltip({ + container: $graph, + placement: 'auto left', + animation: false, + viewport: null + }).on('hide.bs.tooltip', function() { + // keep them visible even if you acidentally mouse over + if ($a.attr('data-tooltip-keepvisible')) { + return false + } + }) + }, + show: function () { + var $a = $(this) + $a.attr('data-tooltip-keepvisible', true) + $a.tooltip('show') + }, + hide: function () { + var $a = $(this) + $a.removeAttr('data-tooltip-keepvisible') + $a.tooltip('hide') + }, + update: function () { + var $this = $(this) + if ($this.attr('data-tooltip-keepvisible')) { + $this.tooltip('show') + return + } + } + }, + zoom: true, + highlight: { + selected: function (col, bg) { + return col + }, + unselected: function (col, bg) { + return jQuery.Color(col).transition(bg, 0.9) + } + }, + ready: null + } + + GraphvizSvg.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + + if (options.url) { + var that = this + $.get(options.url, null, function(data) { + var svg = $("svg", data) + that.$element.html(document.adoptNode(svg[0])) + that.setup() + }, "xml") + } else { + if (options.svg) { + this.$element.html(options.svg) + } + this.setup() + } + } + + GraphvizSvg.prototype.getDefaults = function () { + return GraphvizSvg.DEFAULTS + } + + GraphvizSvg.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.shrink) { + if (typeof options.shrink != 'object') { + options.shrink = { + x: options.shrink, + y: options.shrink + } + } + options.shrink.x = this.convertToPx(options.shrink.x) + options.shrink.y = this.convertToPx(options.shrink.y) + } + return options + } + + GraphvizSvg.prototype.setup = function () { + var options = this.options + + // save key elements in the graph for easy access + var $svg = $(this.$element.children('svg')) + var $graph = $svg.children('g:first') + this.$svg = $svg + this.$graph = $graph + this.$background = $graph.children('polygon:first') // might not exist + this.$nodes = $graph.children('.node') + this.$edges = $graph.children('.edge') + this._nodesByName = {} + this._edgesByName = {} + + // add top level class and copy background color to element + this.$element.addClass('graphviz-svg') + if (this.$background.length) { + this.$element.css('background', this.$background.attr('fill')) + } + + // setup all the nodes and edges + var that = this + this.$nodes.each(function () { that.setupNodesEdges($(this), true) }) + this.$edges.each(function () { that.setupNodesEdges($(this), false) }) + + // remove the graph title element + var $title = this.$graph.children('title') + this.$graph.attr('data-name', $title.text()) + $title.remove() + + if (options.zoom) { + this.setupZoom() + } + + // tell people we're done + if (options.ready) { + options.ready.call(this) + } + } + + GraphvizSvg.prototype.setupNodesEdges = function ($el, isNode) { + var that = this + var options = this.options + + // save the colors of the paths, ellipses and polygons + $el.find('polygon, ellipse, path').each(function () { + var $this = $(this) + // save original colors + $this.data('graphviz.svg.color', { + fill: $this.attr('fill'), + stroke: $this.attr('stroke') + + }) + + // shrink it if it's a node + if (isNode && options.shrink) { + that.scaleNode($this) + } + }) + + // save the node name and check if theres a comment above; save it + var $title = $el.children('title') + if ($title[0]) { + // remove any compass points: + var title = $title.text().replace(/:[snew][ew]?/g,'') + $el.attr('data-name', title) + $title.remove() + if (isNode) { + this._nodesByName[title] = $el[0] + } else { + this._edgesByName[title] = $el[0] + } + // without a title we can't tell if its a user comment or not + var previousSibling = $el[0].previousSibling + while (previousSibling && previousSibling.nodeType != 8) { + previousSibling = previousSibling.previousSibling + } + if (previousSibling != null && previousSibling.nodeType == 8) { + var htmlDecode = function (input) { + var e = document.createElement('div') + e.innerHTML = input + return e.childNodes[0].nodeValue + } + var value = htmlDecode(previousSibling.nodeValue.trim()) + if (value != title) { + // user added comment + $el.attr('data-comment', value) + } + } + } + + // remove namespace from a[xlink:title] + $el.children('a').filter(function () { return $(this).attr('xlink:title') }).each(function () { + var $a = $(this) + $a.attr('title', $a.attr('xlink:title')) + $a.removeAttr('xlink:title') + if (options.tooltips) { + options.tooltips.init.call(this, that.$element) + } + }) + } + + GraphvizSvg.prototype.setupZoom = function() { + var that = this + var $element = this.$element + var $svg = this.$svg + this.zoom = {width: $svg.attr('width'), height: $svg.attr('height'), percentage: null } + this.scaleView(100.0) + $element.mousewheel(function (evt) { + if (evt.shiftKey) { + var percentage = that.zoom.percentage + percentage -= evt.deltaY * evt.deltaFactor + if (percentage < 100.0) { + percentage = 100.0 + } + // get pointer offset in view + // ratio offset within svg + var dx = evt.pageX - $svg.offset().left + var dy = evt.pageY - $svg.offset().top + var rx = dx / $svg.width() + var ry = dy / $svg.height() + + // offset within frame ($element) + var px = evt.pageX - $element.offset().left + var py = evt.pageY - $element.offset().top + + that.scaleView(percentage) + // scroll so pointer is still in same place + $element.scrollLeft((rx * $svg.width()) + 0.5 - px) + $element.scrollTop((ry * $svg.height()) + 0.5 - py) + return false // stop propogation + } + }) + } + + GraphvizSvg.prototype.scaleView = function(percentage) { + var that = this + var $svg = this.$svg + $svg.attr('width', percentage + '%') + $svg.attr('height', percentage + '%') + this.zoom.percentage = percentage + // now callback to update tooltip position + var $everything = this.$nodes.add(this.$edges) + $everything.children('a[title]').each(function () { + that.options.tooltips.update.call(this) + }) + } + + GraphvizSvg.prototype.scaleNode = function($node) { + var dx = this.options.shrink.x + var dy = this.options.shrink.y + var tagName = $node.prop('tagName') + if (tagName == 'ellipse') { + $node.attr('rx', parseFloat($node.attr('rx')) - dx) + $node.attr('ry', parseFloat($node.attr('ry')) - dy) + } else if (tagName == 'polygon') { + // this is more complex - we need to scale it manually + var bbox = $node[0].getBBox() + var cx = bbox.x + (bbox.width / 2) + var cy = bbox.y + (bbox.height / 2) + var pts = $node.attr('points').split(' ') + var points = '' // new value + for (var i in pts) { + var xy = pts[i].split(',') + var ox = parseFloat(xy[0]) + var oy = parseFloat(xy[1]) + points += (((cx - ox) / (bbox.width / 2) * dx) + ox) + + ',' + + (((cy - oy) / (bbox.height / 2) * dy) + oy) + + ' ' + } + $node.attr('points', points) + } + } + + GraphvizSvg.prototype.convertToPx = function (val) { + var retval = val + if (typeof val == 'string') { + var end = val.length + var factor = 1.0 + if (val.endsWith('px')) { + end -= 2 + } else if (val.endsWith('pt')) { + end -= 2 + factor = GraphvizSvg.GVPT_2_PX + } + retval = parseFloat(val.substring(0, end)) * factor + } + return retval + } + + GraphvizSvg.prototype.findEdge = function (nodeName, testEdge, $retval) { + var retval = [] + for (var name in this._edgesByName) { + var match = testEdge(nodeName, name) + if (match) { + if ($retval) { + $retval.push(this._edgesByName[name]) + } + retval.push(match) + } + } + return retval + } + + GraphvizSvg.prototype.findLinked = function (node, includeEdges, testEdge, $retval) { + var that = this + var $node = $(node) + var $edges = null + if (includeEdges) { + $edges = $retval + } + var names = this.findEdge($node.attr('data-name'), testEdge, $edges) + for (var i in names) { + var n = this._nodesByName[names[i]] + if (!$retval.is(n)) { + $retval.push(n) + that.findLinked(n, includeEdges, testEdge, $retval) + } + } + } + + GraphvizSvg.prototype.colorElement = function ($el, getColor) { + var bg = this.$element.css('background') + $el.find('polygon, ellipse, path').each(function() { + var $this = $(this) + var color = $this.data('graphviz.svg.color') + if (color.fill && $this.prop('tagName') != 'path') { + $this.attr('fill', getColor(color.fill, bg)) // don't set fill if it's a path + } + if (color.stroke) { + $this.attr('stroke', getColor(color.stroke, bg)) + } + }) + } + + GraphvizSvg.prototype.restoreElement = function ($el) { + $el.find('polygon, ellipse, path').each(function() { + var $this = $(this) + var color = $this.data('graphviz.svg.color') + if (color.fill) { + $this.attr('fill', color.fill) // don't set fill if it's a path + } + if (color.stroke) { + $this.attr('stroke', color.stroke) + } + }) + } + + + // methods users can actually call + GraphvizSvg.prototype.nodes = function () { + return this.$nodes + } + + GraphvizSvg.prototype.edges = function () { + return this.$edges + } + + GraphvizSvg.prototype.nodesByName = function () { + return this._nodesByName + } + + GraphvizSvg.prototype.edgesByName = function () { + return this._edgesByName + } + + GraphvizSvg.prototype.linkedTo = function (node, includeEdges) { + var $retval = $() + this.findLinked(node, includeEdges, function (nodeName, edgeName) { + var other = null; + var match = '->' + nodeName + if (edgeName.endsWith(match)) { + other = edgeName.substring(0, edgeName.length - match.length); + } + return other; + }, $retval) + return $retval + } + + GraphvizSvg.prototype.linkedFrom = function (node, includeEdges) { + var $retval = $() + this.findLinked(node, includeEdges, function (nodeName, edgeName) { + var other = null; + var match = nodeName + '->' + if (edgeName.startsWith(match)) { + other = edgeName.substring(match.length); + } + return other; + }, $retval) + return $retval + } + + GraphvizSvg.prototype.linked = function (node, includeEdges) { + var $retval = $() + this.findLinked(node, includeEdges, function (nodeName, edgeName) { + return '^' + name + '--(.*)$' + }, $retval) + this.findLinked(node, includeEdges, function (nodeName, edgeName) { + return '^(.*)--' + name + '$' + }, $retval) + return $retval + } + + GraphvizSvg.prototype.tooltip = function ($elements, show) { + var that = this + var options = this.options + $elements.each(function () { + $(this).children('a[title]').each(function () { + if (show) { + options.tooltips.show.call(this) + } else { + options.tooltips.hide.call(this) + } + }) + }) + } + + GraphvizSvg.prototype.bringToFront = function ($elements) { + $elements.detach().appendTo(this.$graph) + } + + GraphvizSvg.prototype.sendToBack = function ($elements) { + if (this.$background.length) { + $element.insertAfter(this.$background) + } else { + $elements.detach().prependTo(this.$graph) + } + } + + GraphvizSvg.prototype.highlight = function ($nodesEdges, tooltips) { + var that = this + var options = this.options + var $everything = this.$nodes.add(this.$edges) + if ($nodesEdges && $nodesEdges.length > 0) { + // create set of all other elements and dim them + $everything.not($nodesEdges).each(function () { + that.colorElement($(this), options.highlight.unselected) + that.tooltip($(this)) + }) + $nodesEdges.each(function () { + that.colorElement($(this), options.highlight.selected) + }) + if (tooltips) { + this.tooltip($nodesEdges, true) + } + } else { + $everything.each(function () { + that.restoreElement($(this)) + }) + this.tooltip($everything) + } + } + + GraphvizSvg.prototype.destroy = function () { + var that = this + this.hide(function () { + that.$element.off('.' + that.type).removeData(that.type) + }) + } + + + // GRAPHVIZSVG PLUGIN DEFINITION + // ============================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('graphviz.svg') + var options = typeof option == 'object' && option + + if (!data && /destroy/.test(option)) return + if (!data) $this.data('graphviz.svg', (data = new GraphvizSvg(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.graphviz + + $.fn.graphviz = Plugin + $.fn.graphviz.Constructor = GraphvizSvg + + + // GRAPHVIZ NO CONFLICT + // ==================== + + $.fn.graphviz.noConflict = function () { + $.fn.graphviz = old + return this + } + +}(jQuery) diff --git a/usage1.png b/usage1.png new file mode 100644 index 0000000000000000000000000000000000000000..85b50d04fad80aff4577d604283d6747cc9ada93 GIT binary patch literal 10998 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 hXe0!&{}GB+50Mk2M(WCd*Pn?H literal 0 HcmV?d00001 From 29d08c6d36e1d83293e57b7c45f119aab396d271 Mon Sep 17 00:00:00 2001 From: lujian Date: Thu, 10 Jan 2019 18:26:04 +0800 Subject: [PATCH 2/2] add gh-pages --- .gitignore | 2 - README.md | 28 - classviz-generation/pom.xml | 25 - .../lujian/classviz/generation/Classviz.java | 43 - .../generation/ClassvizGeneration.java | 87 -- .../lujian/classviz/generation/MainEntry.java | 16 - classviz-grammar/pom.xml | 22 - .../lujian/classviz/grammar/AnalysisUnit.java | 63 - .../classviz/grammar/ClassTypeEnum.java | 11 - .../classviz/grammar/GrammarAnalysis.java | 112 -- .../classviz/grammar/demo/AAbstractClass.java | 4 - .../classviz/grammar/demo/AConcreteClass.java | 4 - .../lujian/classviz/grammar/demo/AEnum.java | 4 - .../classviz/grammar/demo/AInterface.java | 4 - .../classviz/grammar/demo/BInterface.java | 4 - classviz-visualize/pom.xml | 34 - .../classviz/visualize/DigraphFactory.java | 34 - .../visualize/DigraphNodeFactory.java | 23 - .../classviz/visualize/FactoryEntry.java | 44 - .../classviz/visualize/GraphvizFactory.java | 131 -- .../classmeta/DigraphNodeAbstractClass.java | 27 - .../classmeta/DigraphNodeConcreteClass.java | 26 - .../visualize/classmeta/DigraphNodeEnum.java | 26 - .../classmeta/DigraphNodeInterface.java | 28 - .../classviz/visualize/meta/ColorEnum.java | 32 - .../classviz/visualize/meta/Digraph.java | 33 - .../classviz/visualize/meta/DigraphEdge.java | 46 - .../classviz/visualize/meta/DigraphNode.java | 31 - .../classviz/visualize/meta/EdgeDesc.java | 14 - .../classviz/visualize/meta/NodeDesc.java | 39 - design/goal.mmd | 79 - examples/css/graphviz.svg.css | 42 - examples/demo.html | 70 - examples/demo.svg | 1270 ----------------- examples/js/jquery.graphviz.svg.js | 534 ------- examples/usage1.png | Bin 10998 -> 0 bytes examples/usage2.png | Bin 26947 -> 0 bytes pom.xml | 64 - 38 files changed, 3056 deletions(-) delete mode 100644 .gitignore delete mode 100644 README.md delete mode 100644 classviz-generation/pom.xml delete mode 100644 classviz-generation/src/main/java/com/lujian/classviz/generation/Classviz.java delete mode 100644 classviz-generation/src/main/java/com/lujian/classviz/generation/ClassvizGeneration.java delete mode 100644 classviz-generation/src/main/java/com/lujian/classviz/generation/MainEntry.java delete mode 100644 classviz-grammar/pom.xml delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/AnalysisUnit.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/ClassTypeEnum.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/GrammarAnalysis.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AAbstractClass.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AConcreteClass.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AEnum.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AInterface.java delete mode 100644 classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/BInterface.java delete mode 100644 classviz-visualize/pom.xml delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphFactory.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphNodeFactory.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/FactoryEntry.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/GraphvizFactory.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeAbstractClass.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeConcreteClass.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeEnum.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeInterface.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/ColorEnum.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/Digraph.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphEdge.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphNode.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/EdgeDesc.java delete mode 100644 classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/NodeDesc.java delete mode 100644 design/goal.mmd delete mode 100644 examples/css/graphviz.svg.css delete mode 100644 examples/demo.html delete mode 100644 examples/demo.svg delete mode 100644 examples/js/jquery.graphviz.svg.js delete mode 100644 examples/usage1.png delete mode 100644 examples/usage2.png delete mode 100644 pom.xml diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1062418..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/ -*.iml diff --git a/README.md b/README.md deleted file mode 100644 index 18d955b..0000000 --- a/README.md +++ /dev/null @@ -1,28 +0,0 @@ -## Classviz : A Tool for class dependencies visualization - -### maven repository -maven repository -```java - -``` - -### Usage -We can generate class dependency graph via **Classviz**. -```java -Classviz classviz = ClassvizGeneration.scan(pathToJavaFiles); -classviz.setFormat(Format.SVG); -classviz.exportToFile(new File(fileDestination)); -``` -![](examples/usage1.png) - -With the [jquery.graphviz.svg](https://github.com/mountainstorm/jquery.graphviz.svg), we can track class dependencies and its dependents. The tracking classes are highlight. -![](examples/usage2.png) - -### Referred OR Inspired Projects -1. [https://github.com/nidi3/graphviz-java](https://github.com/nidi3/graphviz-java) -2. [https://github.com/javaparser/javaparser](https://github.com/javaparser/javaparser) -3. [https://github.com/plantuml/plantuml](https://github.com/plantuml/plantuml) -4. [https://github.com/mountainstorm/jquery.graphviz.svg](https://github.com/mountainstorm/jquery.graphviz.svg) - - - diff --git a/classviz-generation/pom.xml b/classviz-generation/pom.xml deleted file mode 100644 index e19ed10..0000000 --- a/classviz-generation/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - classviz - com.lujian - 1.0.0 - - 4.0.0 - - classviz-generation - - - - com.lujian - classviz-grammar - - - com.lujian - classviz-visualize - - - - \ No newline at end of file diff --git a/classviz-generation/src/main/java/com/lujian/classviz/generation/Classviz.java b/classviz-generation/src/main/java/com/lujian/classviz/generation/Classviz.java deleted file mode 100644 index 10748ec..0000000 --- a/classviz-generation/src/main/java/com/lujian/classviz/generation/Classviz.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.lujian.classviz.generation; - -import guru.nidi.graphviz.engine.Format; -import guru.nidi.graphviz.engine.Graphviz; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; - -public class Classviz { - - private Graphviz graph; - private Format format; - - public Classviz(Graphviz graph) { - this.graph = graph; - } - - public void setFormat(Format format) { - this.format = format; - } - - public String exportToString() { - checkFormat(); - return this.graph.render(this.format).toString(); - } - - public void exportToFile(File file) throws IOException { - checkFormat(); - this.graph.render(this.format).toFile(file); - } - - public void exportToOutputStream(OutputStream outputStream) throws IOException { - checkFormat(); - this.graph.render(this.format).toOutputStream(outputStream); - } - - private void checkFormat() { - if(this.format == null) { - throw new IllegalStateException("set output format!"); - } - } -} diff --git a/classviz-generation/src/main/java/com/lujian/classviz/generation/ClassvizGeneration.java b/classviz-generation/src/main/java/com/lujian/classviz/generation/ClassvizGeneration.java deleted file mode 100644 index 2cbcd33..0000000 --- a/classviz-generation/src/main/java/com/lujian/classviz/generation/ClassvizGeneration.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.lujian.classviz.generation; - -import com.lujian.classviz.grammar.AnalysisUnit; -import com.lujian.classviz.grammar.GrammarAnalysis; -import com.lujian.classviz.visualize.DigraphFactory; -import com.lujian.classviz.visualize.GraphvizFactory; -import com.lujian.classviz.visualize.classmeta.DigraphNodeAbstractClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeConcreteClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeEnum; -import com.lujian.classviz.visualize.classmeta.DigraphNodeInterface; -import com.lujian.classviz.visualize.meta.Digraph; -import com.lujian.classviz.visualize.meta.DigraphEdge; -import com.lujian.classviz.visualize.meta.DigraphNode; -import guru.nidi.graphviz.engine.Graphviz; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class ClassvizGeneration { - - public static Classviz scan(List pathList) throws IOException{ - List totalUnitList = new ArrayList<>(); - for (String path : pathList) { - totalUnitList.addAll(GrammarAnalysis.parseFile(new File(path))); - } - Digraph digraph = DigraphFactory.useDefault(); - transformToDigraph(totalUnitList, digraph); - Graphviz graph = GraphvizFactory.create(digraph); - return new Classviz(graph); - } - - public static Classviz scan(String... paths) throws IOException{ - return scan(Arrays.asList(paths)); - } - - public static Classviz scan(String path) throws IOException { - return scan(Arrays.asList(path)); - } - - private static void transformToDigraph(List unitList, Digraph digraph) { - unitList.forEach(analysisUnit -> { - if(analysisUnit == null || analysisUnit.getClassName() == null) { - return; - } - DigraphNode node = null; - switch (analysisUnit.getClassType()) { - case T_CLASS: - node = new DigraphNodeConcreteClass(analysisUnit.getClassName()); - break; - case T_ABSTRACT: - node = new DigraphNodeAbstractClass(analysisUnit.getClassName()); - break; - case T_INTERFACE: - node = new DigraphNodeInterface(analysisUnit.getClassName()); - break; - case T_ENUM: - node = new DigraphNodeEnum(analysisUnit.getClassName()); - break; - } - if (analysisUnit.getExtendedType() == null - && (analysisUnit.getImplementedTypeList() == null - || analysisUnit.getImplementedTypeList().isEmpty())) { - digraph.addNode(node); - }else { - digraph.addNode(node); - if(analysisUnit.getExtendedType() != null) { - DigraphEdge edge = new DigraphEdge(); - edge.setSource(node); - edge.addTarget(new DigraphNodeConcreteClass(analysisUnit.getExtendedType())); - digraph.addEdge(edge); - } - if (analysisUnit.getImplementedTypeList() != null && !analysisUnit.getImplementedTypeList().isEmpty()) { - for (String implementType : analysisUnit.getImplementedTypeList()) { - DigraphEdge edge = new DigraphEdge(); - edge.setSource(node); - edge.addTarget(new DigraphNodeInterface(implementType)); - digraph.addEdge(edge); - } - } - } - }); - } - -} diff --git a/classviz-generation/src/main/java/com/lujian/classviz/generation/MainEntry.java b/classviz-generation/src/main/java/com/lujian/classviz/generation/MainEntry.java deleted file mode 100644 index 30c47f6..0000000 --- a/classviz-generation/src/main/java/com/lujian/classviz/generation/MainEntry.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.lujian.classviz.generation; - -import guru.nidi.graphviz.engine.Format; - -import java.io.File; -import java.io.IOException; - -public class MainEntry { - - public static void main(String[] args) throws IOException { - Classviz classviz = ClassvizGeneration.scan("E:\\frameworks\\java\\open-jdk\\openjdk\\jdk\\src\\share\\classes\\java\\util\\concurrent"); - classviz.setFormat(Format.SVG); - classviz.exportToFile(new File("C:\\Users\\LuJian\\Desktop\\1.svg")); - } - -} diff --git a/classviz-grammar/pom.xml b/classviz-grammar/pom.xml deleted file mode 100644 index a1a7f5d..0000000 --- a/classviz-grammar/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - classviz - com.lujian - 1.0.0 - - 4.0.0 - - classviz-grammar - - - - com.github.javaparser - javaparser-core - 3.9.1 - - - - \ No newline at end of file diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/AnalysisUnit.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/AnalysisUnit.java deleted file mode 100644 index 904c0ba..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/AnalysisUnit.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.lujian.classviz.grammar; - -import java.util.List; - -public class AnalysisUnit { - - String className; - ClassTypeEnum classType; - String packageDeclaration; - String extendedType; - List implementedTypeList; - - public ClassTypeEnum getClassType() { - return classType; - } - - public void setClassType(ClassTypeEnum classType) { - this.classType = classType; - } - - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - public String getPackageDeclaration() { - return packageDeclaration; - } - - public void setPackageDeclaration(String packageDeclaration) { - this.packageDeclaration = packageDeclaration; - } - - public String getExtendedType() { - return extendedType; - } - - public void setExtendedType(String extendedType) { - this.extendedType = extendedType; - } - - public List getImplementedTypeList() { - return implementedTypeList; - } - - public void setImplementedTypeList(List implementedTypeList) { - this.implementedTypeList = implementedTypeList; - } - - @Override - public String toString() { - return "AnalysisUnit{" + - "className='" + className + '\'' + - ", classType=" + classType + - ", packageDeclaration='" + packageDeclaration + '\'' + - ", extendedType='" + extendedType + '\'' + - ", implementedTypeList=" + implementedTypeList + - '}'; - } -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/ClassTypeEnum.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/ClassTypeEnum.java deleted file mode 100644 index da10a38..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/ClassTypeEnum.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.lujian.classviz.grammar; - -public enum ClassTypeEnum { - - T_ENUM, - T_INTERFACE, - T_ABSTRACT, - T_CLASS - ; - -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/GrammarAnalysis.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/GrammarAnalysis.java deleted file mode 100644 index 670f79a..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/GrammarAnalysis.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.lujian.classviz.grammar; - -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.*; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.body.EnumDeclaration; -import com.github.javaparser.ast.type.ClassOrInterfaceType; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.List; - -public class GrammarAnalysis { - - public static AnalysisUnit parse(CompilationUnit unit) { - AnalysisUnit result = new AnalysisUnit(); - List nodeList = unit.getChildNodes(); - for (Node node : nodeList) { - if (node instanceof PackageDeclaration) { - result.setPackageDeclaration(((PackageDeclaration) node).getNameAsString()); - } - if (node instanceof ClassOrInterfaceDeclaration) { - NodeList extendedTypes = ((ClassOrInterfaceDeclaration) node).getExtendedTypes(); - if(extendedTypes != null && !extendedTypes.isEmpty()) { - result.setExtendedType(extendedTypes.get(0).asString()); - } - NodeList implementedTypes = ((ClassOrInterfaceDeclaration) node).getImplementedTypes(); - if(implementedTypes != null && !implementedTypes.isEmpty()) { - List implementList = new ArrayList<>(implementedTypes.size()); - for (ClassOrInterfaceType type : implementedTypes) { - implementList.add(type.getNameAsString()); - } - result.setImplementedTypeList(implementList); - } - - //class name - result.setClassName(((ClassOrInterfaceDeclaration) node).getNameAsString()); - //class type - if(((ClassOrInterfaceDeclaration) node).isInterface()) { - result.setClassType(ClassTypeEnum.T_INTERFACE); - }else { - if (((ClassOrInterfaceDeclaration) node).getModifiers().contains(Modifier.abstractModifier())) { - result.setClassType(ClassTypeEnum.T_ABSTRACT); - }else { - result.setClassType(ClassTypeEnum.T_CLASS); - } - } - } - if(node instanceof EnumDeclaration) { - result.setClassName(((EnumDeclaration) node).getNameAsString()); - result.setClassType(ClassTypeEnum.T_ENUM); - } - } - return result; - } - - public static AnalysisUnit parse(String code) { - return parse(JavaParser.parse(code)); - } - - public static List parsePath(Path path) throws IOException { - return parseFile(path.toFile()); - } - - public static List parseFile(File file) throws IOException { - List resultList = new ArrayList<>(); - if(!file.isDirectory()) { - String filename = file.getName(); - int idx = filename.lastIndexOf("."); - if(idx != -1 && filename.substring(idx).equals(".java")) { - resultList.add(parse(JavaParser.parse(file))); - } - return resultList; - } - Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { - String filename = path.getFileName().toString(); - int idx = filename.lastIndexOf("."); - if(idx != -1 && filename.substring(idx).equals(".java")) { - resultList.add(parse(JavaParser.parse(path))); - } - return FileVisitResult.CONTINUE; - } - }); - return resultList; - } - - public static void main(String[] args) { - System.out.println(GrammarAnalysis.parse("package com.lujian.classviz.grammar.demo;\n" + - "\n" + - "public enum AEnum {\n" + - "}\n")); - System.out.println(GrammarAnalysis.parse("package com.lujian.classviz.grammar.demo;\n" + - "\n" + - "public abstract class AConcreteClass extends AAbstractClass implements AInterface, BInterface{\n" + - "}\n")); - - try { - System.out.println(GrammarAnalysis.parseFile(new File("E:\\codes\\java\\idea-tify\\classviz\\classviz-visualize\\src\\main\\java\\com\\lujian\\classviz\\visualize\\classmeta"))); - } catch (IOException e) { - e.printStackTrace(); - } - } - -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AAbstractClass.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AAbstractClass.java deleted file mode 100644 index 5b63260..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AAbstractClass.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.lujian.classviz.grammar.demo; - -public abstract class AAbstractClass { -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AConcreteClass.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AConcreteClass.java deleted file mode 100644 index ef2492f..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AConcreteClass.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.lujian.classviz.grammar.demo; - -public class AConcreteClass extends AAbstractClass implements AInterface, BInterface{ -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AEnum.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AEnum.java deleted file mode 100644 index 3539507..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AEnum.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.lujian.classviz.grammar.demo; - -public enum AEnum { -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AInterface.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AInterface.java deleted file mode 100644 index 066a92b..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/AInterface.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.lujian.classviz.grammar.demo; - -public interface AInterface { -} diff --git a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/BInterface.java b/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/BInterface.java deleted file mode 100644 index 9ed8039..0000000 --- a/classviz-grammar/src/main/java/com/lujian/classviz/grammar/demo/BInterface.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.lujian.classviz.grammar.demo; - -public interface BInterface { -} diff --git a/classviz-visualize/pom.xml b/classviz-visualize/pom.xml deleted file mode 100644 index a8c861b..0000000 --- a/classviz-visualize/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - classviz - com.lujian - 1.0.0 - - 4.0.0 - - classviz-visualize - - - - org.projectlombok - lombok - 1.16.20 - - - - guru.nidi - graphviz-java - 0.8.0 - - - - org.apache.commons - commons-lang3 - 3.7 - - - - \ No newline at end of file diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphFactory.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphFactory.java deleted file mode 100644 index e764ff2..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.lujian.classviz.visualize; - -import com.lujian.classviz.visualize.meta.ColorEnum; -import com.lujian.classviz.visualize.meta.Digraph; -import com.lujian.classviz.visualize.meta.NodeDesc; -import guru.nidi.graphviz.attribute.RankDir; -import guru.nidi.graphviz.attribute.Shape; -import guru.nidi.graphviz.attribute.Style; - -public class DigraphFactory { - - public static Digraph useDefault() { - Digraph digraph = new Digraph(); - - digraph.setBgColor(ColorEnum.DARK_BLUE.getCode()); - digraph.setPad("0.5"); - digraph.setDpi(70.0); - digraph.setRankDir(RankDir.BOTTOM_TO_TOP); - - NodeDesc desc = new NodeDesc(""); - desc.setShape(Shape.ELLIPSE); - desc.setFont("Microsoft YaHei,微软雅黑"); - desc.setWidth("1"); - desc.setFontSize("20"); - desc.setStyle(Style.FILLED); - desc.setFillColor(ColorEnum.YELLOW.getCode()); - desc.setColor(ColorEnum.YELLOW.getCode()); - desc.setPenWidth("1"); - desc.setLabel(""); - digraph.setNodeDesc(desc); - return digraph; - } - -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphNodeFactory.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphNodeFactory.java deleted file mode 100644 index 988621d..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/DigraphNodeFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.lujian.classviz.visualize; - -import com.lujian.classviz.visualize.classmeta.DigraphNodeAbstractClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeConcreteClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeEnum; -import com.lujian.classviz.visualize.classmeta.DigraphNodeInterface; - -public class DigraphNodeFactory { - - public static DigraphNodeInterface createInterface(String id) { - return new DigraphNodeInterface(id); - } - public static DigraphNodeAbstractClass createAbstractClass(String id) { - return new DigraphNodeAbstractClass(id); - } - public static DigraphNodeConcreteClass createConcreteClass(String id) { - return new DigraphNodeConcreteClass(id); - } - public static DigraphNodeEnum createEnum(String id) { - return new DigraphNodeEnum(id); - } - -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/FactoryEntry.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/FactoryEntry.java deleted file mode 100644 index 1dfd719..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/FactoryEntry.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.lujian.classviz.visualize; - -import com.lujian.classviz.visualize.classmeta.DigraphNodeAbstractClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeConcreteClass; -import com.lujian.classviz.visualize.classmeta.DigraphNodeEnum; -import com.lujian.classviz.visualize.classmeta.DigraphNodeInterface; -import com.lujian.classviz.visualize.meta.Digraph; -import com.lujian.classviz.visualize.meta.DigraphEdge; -import guru.nidi.graphviz.engine.Format; -import guru.nidi.graphviz.engine.Graphviz; - -import static com.lujian.classviz.visualize.DigraphNodeFactory.*; - -public class FactoryEntry { - - public static void main(String[] args) { - Digraph digraph = DigraphFactory.useDefault(); - - DigraphNodeInterface di = createInterface("interface"); - DigraphNodeAbstractClass da = createAbstractClass("abstract class"); - DigraphNodeConcreteClass dc = createConcreteClass("concrete class"); - DigraphNodeEnum de = createEnum("enum"); - - digraph.addNode(di); - digraph.addNode(da); - digraph.addNode(dc); - digraph.addNode(de); - - DigraphEdge edge1 = new DigraphEdge(); - edge1.setSource(dc); - edge1.addTarget(da); - - DigraphEdge edge2 = new DigraphEdge(); - edge2.setSource(dc); - edge2.addTarget(di); - - digraph.addEdge(edge1); - digraph.addEdge(edge2); - - Graphviz graph = GraphvizFactory.create(digraph); - System.out.println(graph.render(Format.SVG).toString()); - } - -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/GraphvizFactory.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/GraphvizFactory.java deleted file mode 100644 index 6a94503..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/GraphvizFactory.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.lujian.classviz.visualize; - -import com.lujian.classviz.visualize.meta.*; -import guru.nidi.graphviz.attribute.*; -import guru.nidi.graphviz.engine.Graphviz; -import guru.nidi.graphviz.model.*; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static guru.nidi.graphviz.model.Factory.*; - -public class GraphvizFactory { - - public static Graphviz create(Digraph digraph) { - MutableGraph g = mutGraph("sampleDigraph").setDirected(true).use((gr, ctx) -> { - applyGraphDesc(graphAttrs(), digraph); - applyNodeDesc(nodeAttrs(), digraph.getNodeDesc()); - createDefNode(digraph.getNodeSet()); - createEdge(digraph.getEdgeSet()); - }); - return Graphviz.fromGraph(g); - } - - private static void applyGraphDesc(MutableAttributed attrs, Digraph digraph) { - if(!StringUtils.isBlank(digraph.getName())) { - attrs.add("name", digraph.getName()); - } - if(!StringUtils.isBlank(digraph.getBgColor())) { - attrs.add("bgcolor", digraph.getBgColor()); - } - if(!StringUtils.isBlank(digraph.getPad())) { - attrs.add("pad", digraph.getPad()); - } - if(digraph.getRankDir() != null) { - attrs.add(digraph.getRankDir()); - } - if(digraph.getDpi() != null) { - attrs.add("dpi", digraph.getDpi()); - } - } - - private static void applyNodeDesc(MutableAttributed attrs, NodeDesc desc) { - if(desc.getShape() != null) { - attrs.add(desc.getShape()); - } - if(desc.getStyle() != null) { - attrs.add(desc.getStyle()); - } - if(!StringUtils.isBlank(desc.getFillColor())) { - attrs.add(Color.rgb(desc.getFillColor()).fill()); - } - if(!StringUtils.isBlank(desc.getColor())) { - attrs.add(Color.rgb(desc.getColor())); - } - if(!StringUtils.isBlank(desc.getFontSize())) { - attrs.add("fontsize", desc.getFontSize()); - } - if(!StringUtils.isBlank(desc.getWidth())) { - attrs.add("width", desc.getWidth()); - } - if(!StringUtils.isBlank(desc.getHeight())) { - attrs.add("height", desc.getHeight()); - } - if(!StringUtils.isBlank(desc.getFont())) { - attrs.add("font", desc.getFont()); - } - if(!StringUtils.isBlank(desc.getPenWidth())) { - attrs.add("penwidth", desc.getPenWidth()); - } - if(!StringUtils.isBlank(desc.getLabel())) { - attrs.add(Label.of(desc.getLabel())); - } - } - - private static LinkSource[] createEdge(Set edgeSet) { - if(edgeSet == null) { - return new LinkSource[0]; - } - Set set = new HashSet<>(); - for (DigraphEdge edge : edgeSet) { - List targetList = edge.getTargetList(); - MutableNode node = createNode(edge.getSource()); - for (DigraphNode target : targetList) { - Link link = node.linkTo(createNode(target)); - link.add(target.getEdgeStyle()); - link.add(target.getEdgeArrow()); - link.add(Color.rgb(ColorEnum.WHITE.getCode())); - node.addLink(link); - } - set.add(node); - } - return set.toArray(new LinkSource[0]); - } - - private static MutableNode createNode(DigraphNode node) { - MutableNode mutNode = mutNode(Label.of(node.getId())); - MutableAttributed attrs = mutNode.attrs(); - applyNodeDesc(attrs, node); - if(!StringUtils.isBlank(node.getTooltip())) { - attrs.add("tooltip", node.getTooltip()); - } - if(!StringUtils.isBlank(node.getFillColor())) { - attrs.add(Color.rgb(node.getFillColor()).fill()); - } - if(!StringUtils.isBlank(node.getColor())) { - attrs.add(Color.rgb(node.getColor())); - } -// if(!StringUtils.isBlank(node.getLabel())) { -// attrs.add("label", node.getLabel()); -// } - if(!StringUtils.isBlank(node.getComment())) { - attrs.add("comment", node.getComment()); - } - return mutNode; - } - - private static LinkSource[] createDefNode(Set nodeSet) { - if(nodeSet == null) { - return new LinkSource[0]; - } - Set set = new HashSet<>(); - for (DigraphNode node : nodeSet) { - set.add(createNode(node)); - } - return set.toArray(new LinkSource[0]); - } - -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeAbstractClass.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeAbstractClass.java deleted file mode 100644 index 5ae9b84..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeAbstractClass.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.lujian.classviz.visualize.classmeta; - -import com.lujian.classviz.visualize.meta.ColorEnum; -import com.lujian.classviz.visualize.meta.DigraphNode; -import guru.nidi.graphviz.attribute.Style; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class DigraphNodeAbstractClass extends DigraphNode { - - protected String tooltip = "AbstractClass"; - protected String fillColor = ColorEnum.C_ABSTRACT_CLASS.getCode(); - - public DigraphNodeAbstractClass(String id, String tooltip, String label) { - super(id, tooltip, label); - } - - public DigraphNodeAbstractClass(String id, String tooltip) { - super(id, tooltip); - } - - public DigraphNodeAbstractClass(String id) { - super(id); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeConcreteClass.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeConcreteClass.java deleted file mode 100644 index 1fbcb81..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeConcreteClass.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.lujian.classviz.visualize.classmeta; - -import com.lujian.classviz.visualize.meta.ColorEnum; -import com.lujian.classviz.visualize.meta.DigraphNode; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class DigraphNodeConcreteClass extends DigraphNode { - - protected String tooltip = "Class"; - protected String fillColor = ColorEnum.C_CONCRETE_CLASS.getCode(); - - public DigraphNodeConcreteClass(String id, String tooltip, String label) { - super(id, tooltip, label); - } - - public DigraphNodeConcreteClass(String id, String tooltip) { - super(id, tooltip); - } - - public DigraphNodeConcreteClass(String id) { - super(id); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeEnum.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeEnum.java deleted file mode 100644 index 28de29a..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeEnum.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.lujian.classviz.visualize.classmeta; - -import com.lujian.classviz.visualize.meta.ColorEnum; -import com.lujian.classviz.visualize.meta.DigraphNode; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class DigraphNodeEnum extends DigraphNode { - - protected String tooltip = "Enum"; - protected String fillColor = ColorEnum.C_ENUM.getCode(); - - public DigraphNodeEnum(String id, String tooltip, String label) { - super(id, tooltip, label); - } - - public DigraphNodeEnum(String id, String tooltip) { - super(id, tooltip); - } - - public DigraphNodeEnum(String id) { - super(id); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeInterface.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeInterface.java deleted file mode 100644 index ad3f165..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/classmeta/DigraphNodeInterface.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.lujian.classviz.visualize.classmeta; - -import com.lujian.classviz.visualize.meta.ColorEnum; -import com.lujian.classviz.visualize.meta.DigraphNode; -import guru.nidi.graphviz.attribute.Style; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class DigraphNodeInterface extends DigraphNode { - - protected String tooltip = "Interface"; - protected String fillColor = ColorEnum.C_INTERFACE.getCode(); - protected Style edgeStyle = Style.DASHED; - - public DigraphNodeInterface(String id, String tooltip, String label) { - super(id, tooltip, label); - } - - public DigraphNodeInterface(String id, String tooltip) { - super(id, tooltip); - } - - public DigraphNodeInterface(String id) { - super(id); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/ColorEnum.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/ColorEnum.java deleted file mode 100644 index 27e3bab..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/ColorEnum.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -public enum ColorEnum { - - DARK_BLUE("#2e3e56"), - DARK_GRAY("#fcfcfc"), - WHITE("#ffffff"), - DARK_LINE("#445773"), - RED("#ea555b"), - YELLOW("#edad56"), - GOLD("#AB6D16"), - DARK_GREEN("#29b89d"), - PURPLE("#9362a8"), - PINK("#f2688d"), - GREEN("#a5cf80"), - BLUE("#8eabd9"), - C_INTERFACE("#B4A7E5"), - C_ABSTRACT_CLASS("#22D223"), - C_CONCRETE_CLASS("#ADD1B2"), - C_ENUM("#E3664A") - ; - - private String code; - - ColorEnum(String code) { - this.code = code; - } - - public String getCode() { - return code; - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/Digraph.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/Digraph.java deleted file mode 100644 index ec30953..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/Digraph.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -import guru.nidi.graphviz.attribute.RankDir; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.util.HashSet; -import java.util.Set; - -@Data -@EqualsAndHashCode -public class Digraph { - - String name; - String bgColor; - String pad; - Double dpi; - RankDir rankDir; - - NodeDesc nodeDesc; - EdgeDesc edgeDEsc; - - Set nodeSet = new HashSet<>(); - Set edgeSet = new HashSet<>(); - - public void addNode(DigraphNode node) { - nodeSet.add(node); - } - - public void addEdge(DigraphEdge edge) { - edgeSet.add(edge); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphEdge.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphEdge.java deleted file mode 100644 index d4886a7..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphEdge.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -@Data -@EqualsAndHashCode -@NoArgsConstructor -public class DigraphEdge { - - DigraphNode source; - - List targetList = new ArrayList<>(); - - public DigraphEdge(DigraphNode source) { - this.source = source; - } - - public DigraphEdge(DigraphNode source, List targetList) { - this.source = source; - this.targetList = targetList; - } - - public void addTarget(DigraphNode target) { - targetList.add(target); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - DigraphEdge that = (DigraphEdge) o; - return Objects.equals(source, that.source) && - Objects.equals(targetList, that.targetList); - } - - @Override - public int hashCode() { - return Objects.hash(source, targetList); - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphNode.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphNode.java deleted file mode 100644 index 015dc0e..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/DigraphNode.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -import lombok.Data; -import lombok.EqualsAndHashCode; - - -@Data -@EqualsAndHashCode(callSuper = true) -public class DigraphNode extends NodeDesc { - - protected String tooltip; - protected String comment; - protected String id; - - public DigraphNode(String id, String tooltip, String label) { - super(label); - this.id = id; - this.tooltip = tooltip; - } - - public DigraphNode(String id, String tooltip) { - super(id); - this.id = id; - this.tooltip = tooltip; - } - - public DigraphNode(String id) { - super(id); - this.id = id; - } -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/EdgeDesc.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/EdgeDesc.java deleted file mode 100644 index ed5a641..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/EdgeDesc.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode -public class EdgeDesc { - - protected String color; - protected String penWidth; - protected String fontname; - -} diff --git a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/NodeDesc.java b/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/NodeDesc.java deleted file mode 100644 index bdfb726..0000000 --- a/classviz-visualize/src/main/java/com/lujian/classviz/visualize/meta/NodeDesc.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.lujian.classviz.visualize.meta; - -import guru.nidi.graphviz.attribute.Arrow; -import guru.nidi.graphviz.attribute.Shape; -import guru.nidi.graphviz.attribute.Style; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode -public class NodeDesc { - - protected Shape shape; - protected Style style; - protected Style edgeStyle; - protected Arrow edgeArrow; - protected String font; - protected String fontSize; - protected String width; - protected String height; - protected String fillColor; - protected String color; - protected String penWidth; - protected String label; - - public NodeDesc(String label) { - this.shape = Shape.RECTANGLE; - this.font = "Microsoft YaHei,微软雅黑"; - this.fontSize = "14"; - this.width = "0.6"; - this.style = Style.FILLED; - this.edgeStyle = Style.SOLID; - this.edgeArrow = Arrow.NORMAL.open(); - this.fillColor = (ColorEnum.YELLOW.getCode()); - this.color = ColorEnum.YELLOW.getCode(); - this.label = label; - } - -} diff --git a/design/goal.mmd b/design/goal.mmd deleted file mode 100644 index 80a488e..0000000 --- a/design/goal.mmd +++ /dev/null @@ -1,79 +0,0 @@ -Mind Map generated by NB MindMap plugin -> __version__=`1.1`,showJumps=`true` ---- - -# goal - -## aims - -### class hierachy visualize -> fillColor=`#3B4FD2` - - -### class single path visualize -> fillColor=`#3B4FD2` - - -### class dependency visualize -> fillColor=`#49D248` - - -## decomposition -> leftSide=`true` - - -### class grammar analysis - -#### extends - -#### implements -> leftSide=`true` - - -#### dependencies -> leftSide=`true` - - -### class diagram visualize -> leftSide=`true` - - -#### interface - -#### abstract class -> leftSide=`true` - - -#### concrete class -> leftSide=`true` - - -#### enum -> leftSide=`true` - - -## design -> leftSide=`true` - - -### interface - -#### I - -### abstract class -> leftSide=`true` - - -#### A - -### concrete class -> leftSide=`true` - - -#### C - -### enum -> leftSide=`true` - - -#### E diff --git a/examples/css/graphviz.svg.css b/examples/css/graphviz.svg.css deleted file mode 100644 index ba4da2e..0000000 --- a/examples/css/graphviz.svg.css +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2015 Mountainstorm - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* this element needs tooltip positioning to work */ -.graphviz-svg { - position: relative; -} - -/* stop tooltips wrapping */ -.graphviz-svg .tooltip-inner { - white-space: nowrap; -} - -/* stop people selecting text on nodes */ -.graphviz-svg text { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; -} diff --git a/examples/demo.html b/examples/demo.html deleted file mode 100644 index 298b347..0000000 --- a/examples/demo.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - -

Click node to highlight; Shift-scroll to zoom; Esc to unhighlight

-
- - - - - - - - - diff --git a/examples/demo.svg b/examples/demo.svg deleted file mode 100644 index 4815892..0000000 --- a/examples/demo.svg +++ /dev/null @@ -1,1270 +0,0 @@ - - -sampleDigraph - - -RunnableScheduledFuture - - -RunnableScheduledFuture - - - - -RunnableFuture<V> - - -RunnableFuture<V> - - - - -RunnableScheduledFuture->RunnableFuture<V> - - - - -ConcurrentLinkedQueue - - -ConcurrentLinkedQueue - - - - -Queue - - -Queue - - - - -ConcurrentLinkedQueue->Queue - - - - -Serializable - - -Serializable - - - - -ConcurrentLinkedQueue->Serializable - - - - -AbstractQueue<E> - - -AbstractQueue<E> - - - - -ConcurrentLinkedQueue->AbstractQueue<E> - - - - -LockSupport - - -LockSupport - - - - -ReadWriteLock - - -ReadWriteLock - - - - -AtomicInteger - - -AtomicInteger - - - - -AtomicInteger->Serializable - - - - -Number - - -Number - - - - -AtomicInteger->Number - - - - -CopyOnWriteArrayList - - -CopyOnWriteArrayList - - - - -CopyOnWriteArrayList->Serializable - - - - -Cloneable - - -Cloneable - - - - -CopyOnWriteArrayList->Cloneable - - - - -RandomAccess - - -RandomAccess - - - - -CopyOnWriteArrayList->RandomAccess - - - - -List - - -List - - - - -CopyOnWriteArrayList->List - - - - -RunnableFuture - - -RunnableFuture - - - - -Runnable - - -Runnable - - - - -RunnableFuture->Runnable - - - - -BrokenBarrierException - - -BrokenBarrierException - - - - -Exception - - -Exception - - - - -BrokenBarrierException->Exception - - - - -AbstractExecutorService - - -AbstractExecutorService - - - - -ExecutorService - - -ExecutorService - - - - -AbstractExecutorService->ExecutorService - - - - -Executor - - -Executor - - - - -ExecutorService->Executor - - - - -LinkedBlockingQueue - - -LinkedBlockingQueue - - - - -LinkedBlockingQueue->Serializable - - - - -LinkedBlockingQueue->AbstractQueue<E> - - - - -BlockingQueue - - -BlockingQueue - - - - -LinkedBlockingQueue->BlockingQueue - - - - -Queue<E> - - -Queue<E> - - - - -BlockingQueue->Queue<E> - - - - -ScheduledFuture - - -ScheduledFuture - - - - -Delayed - - -Delayed - - - - -ScheduledFuture->Delayed - - - - -Comparable<Delayed> - - -Comparable<Delayed> - - - - -Delayed->Comparable<Delayed> - - - - -ConcurrentSkipListMap - - -ConcurrentSkipListMap - - - - -ConcurrentSkipListMap->Serializable - - - - -ConcurrentSkipListMap->Cloneable - - - - -AbstractMap<K,V> - - -AbstractMap<K,V> - - - - -ConcurrentSkipListMap->AbstractMap<K,V> - - - - -ConcurrentNavigableMap - - -ConcurrentNavigableMap - - - - -ConcurrentSkipListMap->ConcurrentNavigableMap - - - - -ConcurrentMap<K,V> - - -ConcurrentMap<K,V> - - - - -ConcurrentNavigableMap->ConcurrentMap<K,V> - - - - -AbstractOwnableSynchronizer - - -AbstractOwnableSynchronizer - - - - -AbstractOwnableSynchronizer->Serializable - - - - -AtomicReferenceFieldUpdater - - -AtomicReferenceFieldUpdater - - - - -PriorityBlockingQueue - - -PriorityBlockingQueue - - - - -PriorityBlockingQueue->Serializable - - - - -PriorityBlockingQueue->AbstractQueue<E> - - - - -PriorityBlockingQueue->BlockingQueue - - - - -Phaser - - -Phaser - - - - -RejectedExecutionHandler - - -RejectedExecutionHandler - - - - -AtomicLong - - -AtomicLong - - - - -AtomicLong->Serializable - - - - -AtomicLong->Number - - - - -Condition - - -Condition - - - - -ThreadPoolExecutor - - -ThreadPoolExecutor - - - - -ThreadPoolExecutor->AbstractExecutorService - - - - -RecursiveAction - - -RecursiveAction - - - - -ForkJoinTask<Void> - - -ForkJoinTask<Void> - - - - -RecursiveAction->ForkJoinTask<Void> - - - - -AtomicReferenceArray - - -AtomicReferenceArray - - - - -AtomicReferenceArray->Serializable - - - - -Future - - -Future - - - - -RecursiveTask - - -RecursiveTask - - - - -ForkJoinTask<V> - - -ForkJoinTask<V> - - - - -RecursiveTask->ForkJoinTask<V> - - - - -SynchronousQueue - - -SynchronousQueue - - - - -SynchronousQueue->Serializable - - - - -SynchronousQueue->AbstractQueue<E> - - - - -SynchronousQueue->BlockingQueue - - - - -AtomicMarkableReference - - -AtomicMarkableReference - - - - -RejectedExecutionException - - -RejectedExecutionException - - - - -RuntimeException - - -RuntimeException - - - - -RejectedExecutionException->RuntimeException - - - - -ArrayBlockingQueue - - -ArrayBlockingQueue - - - - -ArrayBlockingQueue->Serializable - - - - -ArrayBlockingQueue->AbstractQueue<E> - - - - -ArrayBlockingQueue->BlockingQueue - - - - -AtomicLongArray - - -AtomicLongArray - - - - -AtomicLongArray->Serializable - - - - -AtomicStampedReference - - -AtomicStampedReference - - - - -ConcurrentLinkedDeque - - -ConcurrentLinkedDeque - - - - -ConcurrentLinkedDeque->Serializable - - - - -Deque - - -Deque - - - - -ConcurrentLinkedDeque->Deque - - - - -AbstractCollection<E> - - -AbstractCollection<E> - - - - -ConcurrentLinkedDeque->AbstractCollection<E> - - - - -AtomicLongFieldUpdater - - -AtomicLongFieldUpdater - - - - -ReentrantLock - - -ReentrantLock - - - - -ReentrantLock->Serializable - - - - -Lock - - -Lock - - - - -ReentrantLock->Lock - - - - -CopyOnWriteArraySet - - -CopyOnWriteArraySet - - - - -CopyOnWriteArraySet->Serializable - - - - -AbstractSet<E> - - -AbstractSet<E> - - - - -CopyOnWriteArraySet->AbstractSet<E> - - - - -ReentrantReadWriteLock - - -ReentrantReadWriteLock - - - - -ReentrantReadWriteLock->Serializable - - - - -ReentrantReadWriteLock->ReadWriteLock - - - - -CancellationException - - -CancellationException - - - - -IllegalStateException - - -IllegalStateException - - - - -CancellationException->IllegalStateException - - - - -Exchanger - - -Exchanger - - - - -DelayQueue - - -DelayQueue - - - - -DelayQueue->AbstractQueue<E> - - - - -DelayQueue->BlockingQueue - - - - -ThreadFactory - - -ThreadFactory - - - - -ForkJoinPool - - -ForkJoinPool - - - - -ForkJoinPool->AbstractExecutorService - - - - -ExecutionException - - -ExecutionException - - - - -ExecutionException->Exception - - - - -ExecutorCompletionService - - -ExecutorCompletionService - - - - -CompletionService - - -CompletionService - - - - -ExecutorCompletionService->CompletionService - - - - -BlockingDeque - - -BlockingDeque - - - - -BlockingQueue<E> - - -BlockingQueue<E> - - - - -BlockingDeque->BlockingQueue<E> - - - - -ConcurrentSkipListSet - - -ConcurrentSkipListSet - - - - -ConcurrentSkipListSet->Serializable - - - - -ConcurrentSkipListSet->Cloneable - - - - -ConcurrentSkipListSet->AbstractSet<E> - - - - -NavigableSet - - -NavigableSet - - - - -ConcurrentSkipListSet->NavigableSet - - - - -FutureTask - - -FutureTask - - - - -FutureTask->RunnableFuture - - - - -AbstractQueuedLongSynchronizer - - -AbstractQueuedLongSynchronizer - - - - -AbstractQueuedLongSynchronizer->Serializable - - - - -AbstractQueuedLongSynchronizer->AbstractOwnableSynchronizer - - - - -Executors - - -Executors - - - - -ForkJoinWorkerThread - - -ForkJoinWorkerThread - - - - -Thread - - -Thread - - - - -ForkJoinWorkerThread->Thread - - - - -AtomicReference - - -AtomicReference - - - - -AtomicReference->Serializable - - - - -LinkedBlockingDeque - - -LinkedBlockingDeque - - - - -LinkedBlockingDeque->Serializable - - - - -LinkedBlockingDeque->AbstractQueue<E> - - - - -LinkedBlockingDeque->BlockingDeque - - - - -ThreadLocalRandom - - -ThreadLocalRandom - - - - -Random - - -Random - - - - -ThreadLocalRandom->Random - - - - -CyclicBarrier - - -CyclicBarrier - - - - -ConcurrentMap - - -ConcurrentMap - - - - -Map<K,V> - - -Map<K,V> - - - - -ConcurrentMap->Map<K,V> - - - - -AtomicIntegerArray - - -AtomicIntegerArray - - - - -AtomicIntegerArray->Serializable - - - - -TransferQueue - - -TransferQueue - - - - -TransferQueue->BlockingQueue<E> - - - - -ForkJoinTask - - -ForkJoinTask - - - - -ForkJoinTask->Serializable - - - - -ForkJoinTask->Future - - - - -ScheduledThreadPoolExecutor - - -ScheduledThreadPoolExecutor - - - - -ScheduledThreadPoolExecutor->ThreadPoolExecutor - - - - -ScheduledExecutorService - - -ScheduledExecutorService - - - - -ScheduledThreadPoolExecutor->ScheduledExecutorService - - - - -ScheduledExecutorService->ExecutorService - - - - -AbstractQueuedSynchronizer - - -AbstractQueuedSynchronizer - - - - -AbstractQueuedSynchronizer->Serializable - - - - -AbstractQueuedSynchronizer->AbstractOwnableSynchronizer - - - - -AtomicIntegerFieldUpdater - - -AtomicIntegerFieldUpdater - - - - -AtomicBoolean - - -AtomicBoolean - - - - -AtomicBoolean->Serializable - - - - -TimeoutException - - -TimeoutException - - - - -TimeoutException->Exception - - - - -Callable - - -Callable - - - - -ConcurrentHashMap - - -ConcurrentHashMap - - - - -ConcurrentHashMap->Serializable - - - - -ConcurrentHashMap->AbstractMap<K,V> - - - - -ConcurrentHashMap->ConcurrentMap - - - - -CountDownLatch - - -CountDownLatch - - - - -LinkedTransferQueue - - -LinkedTransferQueue - - - - -LinkedTransferQueue->Serializable - - - - -LinkedTransferQueue->AbstractQueue<E> - - - - -LinkedTransferQueue->TransferQueue - - - - -TimeUnit - - -TimeUnit - - - - -Semaphore - - -Semaphore - - - - -Semaphore->Serializable - - - - - diff --git a/examples/js/jquery.graphviz.svg.js b/examples/js/jquery.graphviz.svg.js deleted file mode 100644 index bc800a3..0000000 --- a/examples/js/jquery.graphviz.svg.js +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (c) 2015 Mountainstorm - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - - +function ($) { - 'use strict' - - // Cross Browser starts/endsWith support - // ===================================== - String.prototype.startsWith = function(prefix) { - return this.indexOf(prefix) == 0; - }; - - String.prototype.endsWith = function(suffix) { - return this.indexOf(suffix, this.length - suffix.length) !== -1; - }; - - // GRAPHVIZSVG PUBLIC CLASS DEFINITION - // =================================== - - var GraphvizSvg = function (element, options) { - this.type = null - this.options = null - this.enabled = null - this.$element = null - - this.init('graphviz.svg', element, options) - } - - GraphvizSvg.VERSION = '1.0.1' - - GraphvizSvg.GVPT_2_PX = 32.5 // used to ease removal of extra space - - GraphvizSvg.DEFAULTS = { - url: null, - svg: null, - shrink: '0.125pt', - tooltips: { - init: function ($graph) { - var $a = $(this) - $a.tooltip({ - container: $graph, - placement: 'auto left', - animation: false, - viewport: null - }).on('hide.bs.tooltip', function() { - // keep them visible even if you acidentally mouse over - if ($a.attr('data-tooltip-keepvisible')) { - return false - } - }) - }, - show: function () { - var $a = $(this) - $a.attr('data-tooltip-keepvisible', true) - $a.tooltip('show') - }, - hide: function () { - var $a = $(this) - $a.removeAttr('data-tooltip-keepvisible') - $a.tooltip('hide') - }, - update: function () { - var $this = $(this) - if ($this.attr('data-tooltip-keepvisible')) { - $this.tooltip('show') - return - } - } - }, - zoom: true, - highlight: { - selected: function (col, bg) { - return col - }, - unselected: function (col, bg) { - return jQuery.Color(col).transition(bg, 0.9) - } - }, - ready: null - } - - GraphvizSvg.prototype.init = function (type, element, options) { - this.enabled = true - this.type = type - this.$element = $(element) - this.options = this.getOptions(options) - - if (options.url) { - var that = this - $.get(options.url, null, function(data) { - var svg = $("svg", data) - that.$element.html(document.adoptNode(svg[0])) - that.setup() - }, "xml") - } else { - if (options.svg) { - this.$element.html(options.svg) - } - this.setup() - } - } - - GraphvizSvg.prototype.getDefaults = function () { - return GraphvizSvg.DEFAULTS - } - - GraphvizSvg.prototype.getOptions = function (options) { - options = $.extend({}, this.getDefaults(), this.$element.data(), options) - - if (options.shrink) { - if (typeof options.shrink != 'object') { - options.shrink = { - x: options.shrink, - y: options.shrink - } - } - options.shrink.x = this.convertToPx(options.shrink.x) - options.shrink.y = this.convertToPx(options.shrink.y) - } - return options - } - - GraphvizSvg.prototype.setup = function () { - var options = this.options - - // save key elements in the graph for easy access - var $svg = $(this.$element.children('svg')) - var $graph = $svg.children('g:first') - this.$svg = $svg - this.$graph = $graph - this.$background = $graph.children('polygon:first') // might not exist - this.$nodes = $graph.children('.node') - this.$edges = $graph.children('.edge') - this._nodesByName = {} - this._edgesByName = {} - - // add top level class and copy background color to element - this.$element.addClass('graphviz-svg') - if (this.$background.length) { - this.$element.css('background', this.$background.attr('fill')) - } - - // setup all the nodes and edges - var that = this - this.$nodes.each(function () { that.setupNodesEdges($(this), true) }) - this.$edges.each(function () { that.setupNodesEdges($(this), false) }) - - // remove the graph title element - var $title = this.$graph.children('title') - this.$graph.attr('data-name', $title.text()) - $title.remove() - - if (options.zoom) { - this.setupZoom() - } - - // tell people we're done - if (options.ready) { - options.ready.call(this) - } - } - - GraphvizSvg.prototype.setupNodesEdges = function ($el, isNode) { - var that = this - var options = this.options - - // save the colors of the paths, ellipses and polygons - $el.find('polygon, ellipse, path').each(function () { - var $this = $(this) - // save original colors - $this.data('graphviz.svg.color', { - fill: $this.attr('fill'), - stroke: $this.attr('stroke') - - }) - - // shrink it if it's a node - if (isNode && options.shrink) { - that.scaleNode($this) - } - }) - - // save the node name and check if theres a comment above; save it - var $title = $el.children('title') - if ($title[0]) { - // remove any compass points: - var title = $title.text().replace(/:[snew][ew]?/g,'') - $el.attr('data-name', title) - $title.remove() - if (isNode) { - this._nodesByName[title] = $el[0] - } else { - this._edgesByName[title] = $el[0] - } - // without a title we can't tell if its a user comment or not - var previousSibling = $el[0].previousSibling - while (previousSibling && previousSibling.nodeType != 8) { - previousSibling = previousSibling.previousSibling - } - if (previousSibling != null && previousSibling.nodeType == 8) { - var htmlDecode = function (input) { - var e = document.createElement('div') - e.innerHTML = input - return e.childNodes[0].nodeValue - } - var value = htmlDecode(previousSibling.nodeValue.trim()) - if (value != title) { - // user added comment - $el.attr('data-comment', value) - } - } - } - - // remove namespace from a[xlink:title] - $el.children('a').filter(function () { return $(this).attr('xlink:title') }).each(function () { - var $a = $(this) - $a.attr('title', $a.attr('xlink:title')) - $a.removeAttr('xlink:title') - if (options.tooltips) { - options.tooltips.init.call(this, that.$element) - } - }) - } - - GraphvizSvg.prototype.setupZoom = function() { - var that = this - var $element = this.$element - var $svg = this.$svg - this.zoom = {width: $svg.attr('width'), height: $svg.attr('height'), percentage: null } - this.scaleView(100.0) - $element.mousewheel(function (evt) { - if (evt.shiftKey) { - var percentage = that.zoom.percentage - percentage -= evt.deltaY * evt.deltaFactor - if (percentage < 100.0) { - percentage = 100.0 - } - // get pointer offset in view - // ratio offset within svg - var dx = evt.pageX - $svg.offset().left - var dy = evt.pageY - $svg.offset().top - var rx = dx / $svg.width() - var ry = dy / $svg.height() - - // offset within frame ($element) - var px = evt.pageX - $element.offset().left - var py = evt.pageY - $element.offset().top - - that.scaleView(percentage) - // scroll so pointer is still in same place - $element.scrollLeft((rx * $svg.width()) + 0.5 - px) - $element.scrollTop((ry * $svg.height()) + 0.5 - py) - return false // stop propogation - } - }) - } - - GraphvizSvg.prototype.scaleView = function(percentage) { - var that = this - var $svg = this.$svg - $svg.attr('width', percentage + '%') - $svg.attr('height', percentage + '%') - this.zoom.percentage = percentage - // now callback to update tooltip position - var $everything = this.$nodes.add(this.$edges) - $everything.children('a[title]').each(function () { - that.options.tooltips.update.call(this) - }) - } - - GraphvizSvg.prototype.scaleNode = function($node) { - var dx = this.options.shrink.x - var dy = this.options.shrink.y - var tagName = $node.prop('tagName') - if (tagName == 'ellipse') { - $node.attr('rx', parseFloat($node.attr('rx')) - dx) - $node.attr('ry', parseFloat($node.attr('ry')) - dy) - } else if (tagName == 'polygon') { - // this is more complex - we need to scale it manually - var bbox = $node[0].getBBox() - var cx = bbox.x + (bbox.width / 2) - var cy = bbox.y + (bbox.height / 2) - var pts = $node.attr('points').split(' ') - var points = '' // new value - for (var i in pts) { - var xy = pts[i].split(',') - var ox = parseFloat(xy[0]) - var oy = parseFloat(xy[1]) - points += (((cx - ox) / (bbox.width / 2) * dx) + ox) + - ',' + - (((cy - oy) / (bbox.height / 2) * dy) + oy) + - ' ' - } - $node.attr('points', points) - } - } - - GraphvizSvg.prototype.convertToPx = function (val) { - var retval = val - if (typeof val == 'string') { - var end = val.length - var factor = 1.0 - if (val.endsWith('px')) { - end -= 2 - } else if (val.endsWith('pt')) { - end -= 2 - factor = GraphvizSvg.GVPT_2_PX - } - retval = parseFloat(val.substring(0, end)) * factor - } - return retval - } - - GraphvizSvg.prototype.findEdge = function (nodeName, testEdge, $retval) { - var retval = [] - for (var name in this._edgesByName) { - var match = testEdge(nodeName, name) - if (match) { - if ($retval) { - $retval.push(this._edgesByName[name]) - } - retval.push(match) - } - } - return retval - } - - GraphvizSvg.prototype.findLinked = function (node, includeEdges, testEdge, $retval) { - var that = this - var $node = $(node) - var $edges = null - if (includeEdges) { - $edges = $retval - } - var names = this.findEdge($node.attr('data-name'), testEdge, $edges) - for (var i in names) { - var n = this._nodesByName[names[i]] - if (!$retval.is(n)) { - $retval.push(n) - that.findLinked(n, includeEdges, testEdge, $retval) - } - } - } - - GraphvizSvg.prototype.colorElement = function ($el, getColor) { - var bg = this.$element.css('background') - $el.find('polygon, ellipse, path').each(function() { - var $this = $(this) - var color = $this.data('graphviz.svg.color') - if (color.fill && $this.prop('tagName') != 'path') { - $this.attr('fill', getColor(color.fill, bg)) // don't set fill if it's a path - } - if (color.stroke) { - $this.attr('stroke', getColor(color.stroke, bg)) - } - }) - } - - GraphvizSvg.prototype.restoreElement = function ($el) { - $el.find('polygon, ellipse, path').each(function() { - var $this = $(this) - var color = $this.data('graphviz.svg.color') - if (color.fill) { - $this.attr('fill', color.fill) // don't set fill if it's a path - } - if (color.stroke) { - $this.attr('stroke', color.stroke) - } - }) - } - - - // methods users can actually call - GraphvizSvg.prototype.nodes = function () { - return this.$nodes - } - - GraphvizSvg.prototype.edges = function () { - return this.$edges - } - - GraphvizSvg.prototype.nodesByName = function () { - return this._nodesByName - } - - GraphvizSvg.prototype.edgesByName = function () { - return this._edgesByName - } - - GraphvizSvg.prototype.linkedTo = function (node, includeEdges) { - var $retval = $() - this.findLinked(node, includeEdges, function (nodeName, edgeName) { - var other = null; - var match = '->' + nodeName - if (edgeName.endsWith(match)) { - other = edgeName.substring(0, edgeName.length - match.length); - } - return other; - }, $retval) - return $retval - } - - GraphvizSvg.prototype.linkedFrom = function (node, includeEdges) { - var $retval = $() - this.findLinked(node, includeEdges, function (nodeName, edgeName) { - var other = null; - var match = nodeName + '->' - if (edgeName.startsWith(match)) { - other = edgeName.substring(match.length); - } - return other; - }, $retval) - return $retval - } - - GraphvizSvg.prototype.linked = function (node, includeEdges) { - var $retval = $() - this.findLinked(node, includeEdges, function (nodeName, edgeName) { - return '^' + name + '--(.*)$' - }, $retval) - this.findLinked(node, includeEdges, function (nodeName, edgeName) { - return '^(.*)--' + name + '$' - }, $retval) - return $retval - } - - GraphvizSvg.prototype.tooltip = function ($elements, show) { - var that = this - var options = this.options - $elements.each(function () { - $(this).children('a[title]').each(function () { - if (show) { - options.tooltips.show.call(this) - } else { - options.tooltips.hide.call(this) - } - }) - }) - } - - GraphvizSvg.prototype.bringToFront = function ($elements) { - $elements.detach().appendTo(this.$graph) - } - - GraphvizSvg.prototype.sendToBack = function ($elements) { - if (this.$background.length) { - $element.insertAfter(this.$background) - } else { - $elements.detach().prependTo(this.$graph) - } - } - - GraphvizSvg.prototype.highlight = function ($nodesEdges, tooltips) { - var that = this - var options = this.options - var $everything = this.$nodes.add(this.$edges) - if ($nodesEdges && $nodesEdges.length > 0) { - // create set of all other elements and dim them - $everything.not($nodesEdges).each(function () { - that.colorElement($(this), options.highlight.unselected) - that.tooltip($(this)) - }) - $nodesEdges.each(function () { - that.colorElement($(this), options.highlight.selected) - }) - if (tooltips) { - this.tooltip($nodesEdges, true) - } - } else { - $everything.each(function () { - that.restoreElement($(this)) - }) - this.tooltip($everything) - } - } - - GraphvizSvg.prototype.destroy = function () { - var that = this - this.hide(function () { - that.$element.off('.' + that.type).removeData(that.type) - }) - } - - - // GRAPHVIZSVG PLUGIN DEFINITION - // ============================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('graphviz.svg') - var options = typeof option == 'object' && option - - if (!data && /destroy/.test(option)) return - if (!data) $this.data('graphviz.svg', (data = new GraphvizSvg(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - var old = $.fn.graphviz - - $.fn.graphviz = Plugin - $.fn.graphviz.Constructor = GraphvizSvg - - - // GRAPHVIZ NO CONFLICT - // ==================== - - $.fn.graphviz.noConflict = function () { - $.fn.graphviz = old - return this - } - -}(jQuery) diff --git a/examples/usage1.png b/examples/usage1.png deleted file mode 100644 index 85b50d04fad80aff4577d604283d6747cc9ada93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10998 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 hXe0!&{}GB+50Mk2M(WCd*Pn?H diff --git a/pom.xml b/pom.xml deleted file mode 100644 index a035cc6..0000000 --- a/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - 4.0.0 - - com.lujian - classviz - pom - 1.0.0 - - classviz-visualize - classviz-grammar - classviz-generation - - - - ${file_encoding} - 1.8 - 1.8 - UTF-8 - 3.7.0 - - - - - - com.lujian - classviz-grammar - 1.0.0 - - - com.lujian - classviz-visualize - 1.0.0 - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven_compiler_plugin_version} - - true - ${java_source_version} - ${java_target_version} - ${file_encoding} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - - \ No newline at end of file