NameTiddlyTagMindMap2
Requiresexcanvas jit-yc
Version2.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);
      
    bag
    tiddlytagmindmap_public
    created
    Wed, 29 Sep 2010 11:03:27 GMT
    creator
    jon
    modified
    Thu, 15 Sep 2011 11:17:40 GMT
    modifier
    jon
    tags
    excludeLists
    systemConfig