html框架代码
html
<div id="container" class="container">
<canvas id="mycanvas" class="con_box mycanvas"></canvas>
<div id="mydiv" class="con_box mydiv">
<div class="roots roots_js"></div>
</div>
</div>
js代码
javascript
<script type="text/javascript">
$(function () {
layui.use([
"layer",
], function () {
layer = layui.layer;
var ecanvas = document.getElementById("mycanvas");
var ctx = ecanvas.getContext("2d");
// 画线
function lines_canvas() {
// obj
var obj_ = $(".tree_box:nth-child(2)").children();
if (!obj_.length) {
return false; //根节点下没有元素时避免报错
}
var obj_st = obj_.first();
var obj_e = obj_.last();
// left
var left_st = obj_st.position().left + (obj_st.outerWidth(true) / 2);
var left_e = obj_e.position().left + (obj_e.outerWidth(true) / 2);
var left_cen = $(".roots").position().left + ($(".roots").outerWidth(true) / 2);
// top
var top_st = $(".roots").position().top + $(".roots").outerHeight(true);
top_st += window.innerWidth * 0.02; //避免连接线从上面漏出
var top_e = $(".tree_box:nth-child(2)").position().top + (window.innerWidth * 0.15);
var top_cen = top_st + ((top_e - top_st) / 2);
// 从起始点出现的竖线
ctx.beginPath();
ctx.moveTo(left_cen, top_st);
ctx.lineTo(left_cen, top_cen);
ctx.stroke();
// 覆盖所有子元素的横线
ctx.beginPath();
ctx.moveTo(left_st, top_cen);
ctx.lineTo(left_e, top_cen);
ctx.stroke();
$.each(obj_, function (key, vo) {
// 从覆盖线到每一个子元素
var left_tmp = $(vo).position().left + ($(vo).outerWidth(true) / 2);
ctx.beginPath();
ctx.moveTo(left_tmp, top_cen);
ctx.lineTo(left_tmp, top_e);
ctx.stroke();
});
$.each($(".start"), function (key, vo) {
// console.log(vo);
// obj
var obj_p = $(vo).parent();
var obj_np = obj_p.next();
var obj_cnp = obj_np.children();
var obj_st = obj_cnp.first();
var obj_e = obj_cnp.last();
// left
var s_x = $(vo).position().left + ($(vo).outerWidth(true) / 2);
var first_x = obj_st.position().left + (obj_st.outerWidth(true) / 2);
var st_x = Math.min(s_x, first_x);
var last_x = obj_e.position().left + (obj_e.outerWidth(true) / 2);
var e_x = Math.max(s_x, last_x);
// top
var st_y = obj_p.position().top + obj_p.outerHeight(true);
st_y += window.innerWidth * 0.01; //避免连接线从上面漏出
st_y += -$(obj_p).height() + $(vo).outerHeight(true); //兼容高度不同的元素
var e_y = $(obj_np).position().top + (window.innerWidth * 0.15);
var cen_y = st_y + ((e_y - st_y) / 2);
// 从起始点出现的竖线
ctx.beginPath();
ctx.moveTo(s_x, st_y);
ctx.lineTo(s_x, cen_y);
ctx.stroke();
// 覆盖所有子元素的横线
ctx.beginPath();
ctx.moveTo(st_x, cen_y);
ctx.lineTo(e_x, cen_y);
ctx.stroke();
$.each(obj_cnp, function (key, vo) {
// 从覆盖线到每一个子元素
var left_tmp = $(vo).position().left + ($(vo).outerWidth(true) / 2);
ctx.beginPath();
ctx.moveTo(left_tmp, cen_y);
ctx.lineTo(left_tmp, e_y);
ctx.stroke();
});
});
// ecanvas.toDataURL();
}
// canvas
function init_canvas() {
console.log("init_canvas");
$("#mycanvas").attr("width", $("#mydiv").outerWidth(true));
$("#mycanvas").attr("height", $("#mydiv").outerHeight(true));
ctx.save();
ctx.restore();
ctx.strokeStyle = "#a4aabb"; //线颜色
lines_canvas();
}
// 数据添加到页面
function show_datas(infos, len) {
// console.log(infos);
if (infos.depth == 0) {
$(".roots_js").html(infos.names);
$(".roots_js").attr("iid", infos.id);
} else {
var obj = $(".tree_box:nth-child(" + (infos.depth + 1) + ")");
if (!obj.length) {
$(".mydiv").append(`<div class="tree_box"></div>`);
}
var obj = $(".tree_box:nth-child(" + (infos.depth + 1) + ")");
var clas = "";
if (infos.children) {
clas += "start";
}
if (infos.last == 1) {
clas += "lebg" + infos.linkeva;
}
// var ids = "node" + infos.id;
var ids = infos.id;
if (!$("#" + ids).length) {
obj.append(`<div id="` + ids +
`" class="tree_cons end ` + clas +
`" depth="` + infos.depth +
`" onclick="get_tree(` + infos.id + `,this)">` +
infos.names +
`</div>`);
}
}
if (infos.children) {
$.each(infos.children, function (key, vo) {
show_datas(vo);
});
}
lens++;
if (len == lens) {
init_canvas();
}
}
// 获取数据并调整页面内容
window.get_tree = function (iid, that) {
// console.log($(".roots").attr("iid"));
// console.log(iid);
// console.log(that);
if (iid == $(".roots").attr("iid")) {
console.log("重复");
return false;
}
if (typeof (ctx) != "undefined") {
ctx.save();
ctx.restore();
}
if (typeof (that) != "undefined") {
// console.log(1);
var obj = $(that).parent();
obj.nextAll().remove();
$.each(obj.children(), function (key, vo) {
$(vo).removeClass("start");
});
} else {
// console.log(2);
$(".tree_box").remove();
}
$.post("/index/pro/gets_tree", {
iid: iid,
}, function (params) {
// console.log(params);
// console.log(params.nodes);
// console.log(params.len);
lens = 0;
if (params.nodes.children) {
$(that).addClass("start");
}
show_datas(params.nodes, params.len);
}, "json");
}
get_tree(`{$iid}`);
// $(".block2_item").click(function () {
// get_tree($(this).attr("iid"));
// });
});
});
</script>
php代码
php
public $t_pri = "ids"; //主键
public $t_ck = "children"; //子数据集key
public $t_fields; //查询字段
function _initialize()
{
parent::_initialize();
$this->t_fields = [
"id",
"id" => $this->t_pri,
"names",
// "names" => "name", //echarts
// "names" => "id", //antv g6
// "names" => "label", //antv g6
"last",
"depth",
"nuop",
"linkeva",
];
}
// 树图数据获取
function gets_tree()
{
$iid = intval(input("iid"));
if (!$iid) {
$iid = Db::name("industrial")->where("iid", "")->value("id");
}
$this->assign("iid", $iid);
$t_arr = $this->datas_tree(0, $iid);
$infos = [];
if (!empty($t_arr[0])) {
$infos = &$t_arr[0];
}
if (isset($infos[$this->t_pri])) {
if ($infos["depth"] == 0) {
$infos["x"] = 1000;
}
}
$res = [];
// $res["infos"] = $infos;
$res["nodes"] = $infos;
$res["len"] = count($this->to_onelv($t_arr));
// $res["lists"] = $t_arr;
// $res["nodes"] = $this->to_pos($infos);
// $res["edges"] = $this->to_edges($infos);
// $res["nodes"] = $this->to_onelv($t_arr);
$res["code"] = 0;
return $res;
}
// 树图数据获取
function datas_tree($iid = 0, $id = 0)
{
$whe["iid"] = $iid;
$whe["id"] = $id;
$whe = array_filter($whe);
$lists = Db::name("industrial")->field($this->t_fields)->where($whe)->select();
if (!empty($lists[0][$this->t_pri])) {
$t_arr = $this->datas_tree($lists[0][$this->t_pri]);
if (!empty($t_arr)) {
$lists[0][$this->t_ck] = $t_arr;
}
}
return $lists;
}
// 树状结构数据展开
function to_onelv($lists)
{
$len = 0;
foreach ($lists as $key => &$value) {
if (!empty($value["children"])) {
$len++;
$lists = array_merge($lists, $value["children"]);
unset($value["children"]);
}
}
if ($len) {
$lists = $this->to_onelv($lists);
}
return $lists;
}
代码效果
