This repo is archived. You can view files and clone it, but cannot push or open issues or pull requests.
SXS20240115/SRC/iMES_PAD/JSplugins/d3-MindMap/d3-MindMap.js
2024-01-24 16:47:50 +08:00

283 lines
12 KiB
JavaScript

/*!
* D3 Mind Map
* v1.0.0
* author Dustdusk
*/
var d3 = require('d3');
(function(window,angular, d3){
'use strict';
angular.module('material.components.mindmap', [])
.provider('$mdMindMap', function(){
var loadMindMap = function(options){
var m = options.margin||[8, 16, 12, 16], //margin
i = 0, body_id = options.body_id||'mind-map',
root, _max_x = [0, 0], _max_y = [0, 0],
_node_width = options.node_width||150, _node_height = options.node_height||24, _link_size = options.link_size||75;
var selectNode = function(target){
if(target){
var sel = d3.selectAll('#'+ body_id + ' svg .node').filter(function(d){return d.id==target.id})[0][0];
if(sel){
select(sel);
}
}
};
var select = function(node){
// Find previously selected, unselect
d3.select(".selected").classed("selected", false);
// Select current item
d3.select(node).classed("selected", true);
};
//node click
var handleClick = function(d, index){
select(this);
if(d._children === undefined && d.children === undefined){
if(typeof options.node.click === 'function'){
options.node.click(d, index, function(node_data){
if(!node_data)
return;
if(!Array.isArray(node_data))
node_data = [node_data];
if(node_data.length == 0)
return;
d.children = [];
for(var i = 0; i < node_data.length;i++){
var _new_node = d3.hierarchy(node_data[i], function(d){
return d[options.node.children];
});
var _max_height = 0;
d.ancestors().forEach(function(sd){
if(sd.height == 0){
_max_height = sd.height + _new_node.height+1;
sd.height = _max_height;
} else if(sd.height <= _max_height){
sd.height = _max_height;
}
_max_height +=1;
});
_new_node.descendants().forEach(function(sd){
sd.depth = d.depth + 1 + sd.depth;
if(!sd.parent)
sd.parent = d;
//sd.id = Date.now();
});
d.children.push(_new_node);
}
update(d);
});
}
} else {
toggle(d);
update(d);
}
};
var tree= d3.tree().nodeSize([_node_height+8, _node_width + _link_size]);
// celc link path
var connector = function (d, i){
var source = {x : d.source.x, y : d.source.y + _node_width};
var target = {x : d.target.x, y : d.target.y};
var hy = (target.y-source.y)/2;
return "M" + source.y + "," + source.x
+ "H" + (source.y+hy)
+ "V" + target.x + "H" + target.y;
};
//建立基本的SVG
var _body = d3.select('#'+ body_id);
var _vis = _body.html('').append('svg:svg');
var vis = _vis.append("svg:g")
.attr("transform", "translate(" + (0+m[3]) + "," + (_vis.node().getBoundingClientRect().height/2+m[0]) + ")") //設定起始點
;
var toArray = function(item, arr){
if(arr == undefined){
_max_x = [0, 0];
_max_y = [0, 0];
arr = [];
}
var i = 0, l = item.children?item.children.length:0;
arr.push(item);
item.y = 1 * item.y;
//_max_depth = _max_depth < item.depth?item.depth:_max_depth;
if(item.x < 0 && item.x < _max_x[0]){
_max_x[0] = item.x;
} else if(item.x > 0 && item.x > _max_x[1]){
_max_x[1] = item.x;
}
if(item.y < 0 && item.y < _max_y[0]){
_max_y[0] = item.y;
} else if(item.y > 0 && item.y > _max_y[1]){
_max_y[1] = item.y;
}
for(; i < l; i++){
toArray(item.children[i], arr);
}
//if()
return arr;
};
// Toggle node children.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
// load JSON data
var loadJSON = function(json){
if(json){
root = json;
root = d3.hierarchy(root, function(d){
return d[options.node.children];
});
root.x0 = 0;
root.y0 = 0;
//update tree
update(root, true);
}
};
// update node
// Source : 資料來源
// slow : 展示速度
function update(source, slow) {
var duration = (d3.event && d3.event.altKey) || slow ? 600 : 200;
// Compute the new tree layout.
// all nodes
var _treeData = tree(root);
var nodes = _treeData.descendants(),
_links = _treeData.descendants().slice(1);
//nodes.forEach(function(d){ d.y = d.depth * 180});
toArray(nodes[0]);
var _height = _max_x[1] - _max_x[0] + _node_height;
var _with = _max_y[1] - _max_y[0] + _node_width;
//tree.size([h, _with]);
_vis.transition()
.duration(duration)
.attr("width", _with + m[1] + m[3])
.attr("height", _height + m[0] + m[2]);
vis.transition()
.duration(duration)
.attr("transform", "translate(" + (0+m[3]) + "," + (_node_height+m[0]-_max_x[0]) + ")");
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", function(d){ return d.selected?"node selected":"node"; })
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", handleClick);
//節點
nodeEnter.append("svg:rect")
.attr("dx", "0")
.attr("y", 0-(_node_height/2))
.attr("rx", "8")
.attr("ry", "8" )
.attr("width", _node_width)
.attr("height", _node_height);
//.append("svg:circle").attr("r", 1e-6);
//.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
//節點文字
nodeEnter.append("svg:text")
.attr("dx", 8)
.attr("dy", 3) //文字下移
.attr("text-anchor", "left") //靠左
.text(function(d) {
if(typeof options.node.label === 'function')
return options.node.label(d.data);
else
return d.data[options.node.label];
})
.style("fill-opacity", 1);
// Transition nodes to their new position.
var nodeUpdate = nodeEnter.merge(node);
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
//nodeUpdate.select("text").text(function(d) { return (d.data.name); });
//nodeUpdate.select("rect");
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("rect");
//.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(_links, function(d) { return d.id; });
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return connector({source: o, target: o});
});
var linkUpdate = linkEnter.merge(link);
// Transition links to their new position.
linkUpdate.transition()
.duration(duration)
.attr("d", function(d) {
return connector({source: d, target: d.parent});
});
// Transition exiting nodes to the parent's new position.
var linkExit = link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return connector({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
loadJSON(options.data);
}
this.$get = ['$rootScope', '$timeout', function($rootScope, $timeout){
return {
load:loadMindMap
};
}];
});
})(window, window.angular, d3);