| Name | TiddlyTagMindMap2 |
| Requires | excanvas jit-yc |
| Version | 2.0.4 |
Parameters
See http://mindmaps.tiddlyspace.com#[[How to use]]- fieldType
StyleSheet
.ttmm {overflow: hidden;
position: relative;
height: 200px;
}
.ttmm .node {
cursor: pointer;
font-size: 0.7em;
}
.nodeMissing {
color: #ccc;
}
.nodeVisited {
color: Purple;
}
.depth0 {
border: solid 1px black;
}
Todo
- html labels have id of the node. This is really bad and should be fixed in the jit core.
(function($){
var tiddler = {title: "TiddlyTagMindMap2Plugin"};
var name = "StyleSheetTiddlyTagMindMap";
config.shadowTiddlers[name] = store.getTiddlerText(tiddler.title +
"##StyleSheet");
store.addNotification(name, refreshStyles);
config.shadowTiddlers.TiddlyTagMindMapNodeTemplate = "<<view title text>>";
var macro = config.macros.TiddlyTagMindMap = {
rootNode: "TiddlyTagMindMapRootNode",
defaultOptions: {
id: null,
rootNode: null,
field: [ "tags" ], // dictates the parent node
fieldsAreList: true,
levelDistance: 40,
width: null,
height: null,
nodeType: "square",
nodeColor: "#ddeeff",
centerOn: false,
edgeColor: '#C17878',
directed: false,
edgeType: null,
edgeWidth: 1.5,
template: "TiddlyTagMindMapNodeTemplate",
filter: false,
maxNodeNameLength: false,
labelDepth: false,
exclude: "excludeLists",
orientation: "v", // left, top, right or bottom
maxDepth: 3,
vizType: "radial",
animate: true, //*
ignoreLoneNodes: true, //*
caseSensitive: false, //*
hideRoot: true,
valuePrefix: false,
nodeHoverColor: "#ddeeff",
nodeClickColor: "#ddeeff",
siblingOffset: 50
},
init: function() {
macro._active = {};
var _displayTiddler = Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle,animationSrc) {
var el = _displayTiddler.apply(this, arguments);
var id = typeof(tiddler) == 'string' ? tiddler : tiddler.title;
macro.centerAll(id);
return el;
};
var _saveTiddler = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title, newTitle, newBody, modifier,
modified, tags, fields, clearChangeCount, created, creator) {
var tid = _saveTiddler.apply(this, arguments);
try {
macro.updateAllGraphs();
} catch(e) {};
return tid;
};
var _removeTiddler = TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler = function(title) {
var tid = store.getTiddler(title);
var flag = _removeTiddler.apply(this, arguments);
try {
macro.updateAllGraphs(title);
} catch(e) {};
return flag;
};
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var options = macro.getOptions(place, paramString);
var data = macro.getData(options);
var id = options.id || "ttmm2_%0".format([Math.random()]);
if(macro._active[id]) {
$(document.getElementById(id)).empty();
}
var container = $("<div />").addClass("ttmm").attr("id", id).
css({width: options.width, height: options.height}).appendTo(place)[0];
$(container).dblclick(function(ev) {
ev.stopPropagation();
});
macro.renderGraph(container, data, options);
},
getNodeLabelId: function(containerId,id) {
return "node-%0-%1".format([containerId, id])
},
updateAllGraphs: function(changed) {
for(var i in macro._active) {
var el = document.getElementById(i);
if(el) {
var cache = macro._active[i];
var deleted = document.getElementById(macro.getNodeLabelId(i, changed));
if(cache) {
var options = cache.options;
var viz = cache.viz;
var data = macro.getData(options);
macro._refresh(viz, data, options);
viz.refresh();
$(deleted).remove();
}
} else {
macro._active[i] = false;
}
}
},
centerAll: function(id) {
for(var i in macro._active) {
var el = document.getElementById(i);
if(el) {
var cache = macro._active[i];
if(cache) {
var viz = cache.viz;
if(viz.graph.hasNode(id)) {
viz.onClick(id);
}
}
} else {
macro._active[i] = false;
}
}
},
renderGraph: function(container, data, options) {
if(options.vizType == "hypertree") {
macro._renderHypertree(container, data, options);
} else if(options.vizType == "spacetree") {
macro._renderSpaceTree(container, data, options);
} else if(options.vizType == "sunburst") {
macro._renderSunburst(container, data, options);
} else {
macro._renderRGraph(container, data, options);
}
},
_getViz: function(type, container, options) {
var containerId = $(container).attr("id");
var _events = {}, _tips = {}, _edge = {}, _navigation = {};
if(options.vizType != "sunburst") {
_navigation = {
enable: true,
panning: true
};
if(options.vizType != "spacetree") {
_navigation.zooming = 10;
}
_edge = {
color: options.edgeColor,
lineWidth: options.edgeWidth,
type: options.edgeType,
overridable: true,
dim: 15
};
}
var viz = new $jit[type]({
orientation: "top",
align: "left",
siblingOffset: options.siblingOffset,
levelsToShow: options.maxDepth,
injectInto: containerId,
Navigation: _navigation,
duration: 300,
width: options.width,
height: options.height,
/*transition: options.vizType == "spacetree" ? $jit.Trans.Quart.easeInOut : null,*/
NodeStyles: {
enable: true,
type: "Native",
stylesClick: {
color: options.nodeClickColor
},
stylesHover: {
color: options.nodeHoverColor
}
},
levelDistance: options.levelDistance,
Label: {
type: "HTML"
},
Node: {
color: options.nodeColor,
type: options.nodeType,
overridable: true,
width: options.nodeWidth ? options.nodeWidth : options.nodeSize,
dim: options.nodeSize,
height: options.nodeHeight ? options.nodeHeight : options.nodeSize
},
Edge: _edge,
onCreateLabel: function(domElement, node){
var el = $(domElement).empty();
if(!options.maxNodeNameLength) {
var ctx = store.tiddlerExists(node.id) ? store.getTiddler(node.id) : new Tiddler(node.id);
var template = store.getTiddlerText(options.template);
template = template ? template : store.getTiddlerText("TiddlyTagMindMapNodeTemplate");
wikify(template, domElement, null, ctx);
} else {
var text = el.text();
var maxLength = options.maxNodeNameLength;
if(maxLength) {
if(text.length > maxLength) {
var diff = (text.length - maxLength);
text = "%0...".format([text.slice(0, text.length - diff)]);
}
}
el.text(text);
}
el.attr("id", macro.getNodeLabelId(containerId, node.id));
var rgraph = this;
var wasClick = false;
$(domElement).click(function(ev){
wasClick = true;
window.setTimeout(function() {
if(wasClick) {
var cache = macro._active[containerId];
if(cache && cache.visitedNodes) {
cache.visitedNodes[node.id] = true;
}
options.centerOn = node.id;
if(viz.onClick) {
viz.onClick(node.id);
}
}
}, 300);
});
$(domElement).dblclick(function(ev) {
wasClick = false;
story.displayTiddler(ev.target, node.id);
ev.stopPropagation();
return false;
});
},
onPlaceLabel: function(domElement, node){
var el = $(domElement);
var depth = node._depth;
if(options.labelDepth && depth > options.labelDepth) {
el.hide();
return;
}
el.show();
var existingDepth = el.attr("node-depth");
if(existingDepth) {
el.removeClass("depth%0".format([existingDepth]));
}
el.attr("node-depth", depth);
el.addClass("depth%0".format([depth]));
if(options.hideRoot && node.data.root) {
el.hide();
}
if(node.data.missing) {
el.addClass("nodeMissing");
if(options.missingColor) {
el.css({ color: "#ccc" });
}
}
var cache = macro._active[containerId];
if(cache && cache.visitedNodes && cache.visitedNodes[node.id]) {
el.addClass("nodeVisited");
}
}
});
return viz;
},
_refresh: function(viz, data, options) {
viz.loadJSON(data);
if(options.vizType == "spacetree") {
viz.compute();
viz.geom.translate(new $jit.Complex(-200, 0), "current");
viz.onClick(viz.root);
} else {
viz.labels = false; // hack
//compute positions and plot.
try {
viz.refresh();
} catch(e) {}
}
if(options.centerOn) {
viz.onClick(options.centerOn);
}
},
_patch: function(viz) {
// customisations
var _plotLine = viz.constructor.Plot.prototype.plotLine;
var _plotNode = viz.constructor.Plot.prototype.plotNode;
viz.constructor.Plot.prototype.plotLine = function(adj, canvas, animating) {
if(adj.nodeFrom.id != macro.rootNode && adj.nodeTo.id != macro.rootNode) {
_plotLine.apply(this, arguments);
}
}
viz.constructor.Plot.prototype.plotNode = function(node, canvas, animating) {
if(node.id != macro.rootNode) {
_plotNode.apply(this, arguments);
}
};
},
_renderHypertree: function(container, data, options) {
var ht = macro._getViz("Hypertree", container, options);
macro._patch(ht);
var id = $(container).attr("id");
macro._active[id] = {
data: data,
viz: ht,
options: options,
visitedNodes: {}
};
macro._refresh(ht, data, options);
//end
ht.controller.onAfterCompute();
},
_renderSpaceTree: function(container, data, options) {
var viz = macro._getViz("ST", container, options);
var id = $(container).attr("id");
macro._active[id] = {
data: data,
viz: viz,
options: options,
visitedNodes: {}
};
macro._refresh(viz, data, options);
},
_renderSunburst: function(container, data, options) {
var sunburst = macro._getViz("Sunburst", container, options);
//load JSON data
var id = $(container).attr("id");
macro._active[id] = {
data: data,
viz: sunburst,
options: options,
visitedNodes: {}
};
macro._refresh(sunburst, data, options);
},
_renderRGraph: function(container, data, options) {
var rgraph = macro._getViz("RGraph", container, options);
macro._patch(rgraph);
//load JSON data
var id = $(container).attr("id");
macro._active[id] = {
data: data,
viz: rgraph,
options: options,
visitedNodes: {}
};
macro._refresh(rgraph, data, options);
},
refresh: function(container) {
return;
var id = $(container).attr("id");
var cache = macro._active[id];
if(cache) {
var data = cache.data;
var options = cache.options;
var rgraph = cache.viz;
}
},
getData: function(options) {
var root = options.rootNode || macro.rootNode;
options = options ? options : macro.defaultOptions;
options._tiddlers = options.filter ? store.filterTiddlers(options.filter) : store.getTiddlers(null, options.exclude);
return macro._createNode(root, options);
},
getOptions: function(container, paramString) {
var listOptions = ["field"]; // will be saved as lists
var numberOptions = ["labelDepth", "width", "height", "levelDistance", "edgeWidth", "siblingOffset", "maxDepth", "nodeWidth", "nodeHeight", "nodeSize"];
var args = paramString.parseParams("name", null, true, false, true)[0];
var options = {};
merge(options, macro.defaultOptions);
for(var id in args) {
if(true) {
var p = args[id];
if(listOptions.contains(id)) {
options[id] = p;
} else if(numberOptions.contains(id)){
options[id] = parseFloat(p[0]);
} else {
options[id] = p[0];
}
}
}
options.nodeSize = options.nodeSize || options.nodeWidth;
options.fieldsAreList = options.fieldType && options.fieldType == "string" ? false : true;
options.width = options.width ? parseInt(options.width) : $(container).width();
options.height = options.height ? parseInt(options.height) : $(container).height();
options.edgeType = options.directed ? "arrow" : options.edgeType;
options.hideRoot = options.hideRoot && options.hideRoot == "no" ? false : true;
// note hyperline doesn't work for RGraph
var defaultEdgeType = options.vizType == "hypertree" ? "hyperline" : "line";
if(!options.edgeType) {
options.edgeType = defaultEdgeType;
} else {
options.edgeType = options.edgeType == "hyperline" && options.vizType != "hypertree" ? "line" : options.edgeType;
}
if(options.vizType == "sunburst") {
options.nodeType = "gradient-multipie"; //"multipie";
options.nodeSize = false;
}
return options;
},
lookupFieldValue: function(tiddler, options) {
var allValues = [];
for(var i = 0; i < options.field.length; i++) {
var fieldName = options.field[i];
var values = tiddler[fieldName] ? tiddler[fieldName] : tiddler.fields[fieldName];
if(options.fieldsAreLists) {
values = typeof(values) == "string" ? values.readBracketedList() : values;
} else {
values = typeof(values) == "string" ? [ values ] : values;
}
if(values) {
for(var j = 0; j < values.length; j++) {
allValues.pushUnique(values[j]);
}
}
}
return allValues;
},
lookupTiddlers: function(tiddlers, value, options) {
var matches = [];
for(var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var values = macro.lookupFieldValue(tiddler, options);
if(values && values.indexOf(value) > -1) {
matches.push(tiddler);
}
}
return matches;
},
_getChildNodes: function(title, options) {
var children = [];
var tiddlers = options._tiddlers
if(title == macro.rootNode) { // get all tiddlers with no tags
var tags = {};
for(var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var values = macro.lookupFieldValue(tiddler, options);
if(values.length === 0) {
var node = macro._createNode(tiddler.title, options);
node.data.orphan = true;
if(node) {
children.push(node);
}
} else {
for(var j = 0; j < values.length; j++) {
var value = values[j];
var tiddler = store.getTiddler(value);
if(!tiddler) {
var node = macro._createNode(value, options);
if(node) {
node.data.orphan = true;
children.push(node);
}
}
}
}
}
} else {
var lookup = options.valuePrefix ? "%0%1".format([options.valuePrefix, title]) : title;
var matches = macro.lookupTiddlers(tiddlers, lookup, options);
if(matches) {
// TODO: support strings to array
for(var i = 0; i < matches.length; i++) {
var node = macro._createNode(matches[i].title, options);
if(node) {
children.push(node);
}
}
}
}
return children;
},
_createNode: function(title, options) {
var children = macro._getChildNodes(title, options);
var node = {
id: title,
name: title,
data: {
missing: store.tiddlerExists(title) ? false : true,
visited: false,
root: title == macro.rootNode,
weight: children.length,
size: 200,
"$angularWidth": 7490
},
children: children
};
return node;
}
};
})(jQuery);