1. Function introduction:
The function is very simple, it is a classification structure display package that supports cool animation effects, learn and research snap.svg .js results. Pure javascript program, can run in html5 webpage. IE8 and below browsers are not supported, and the mobile phone runs better. Depends on jQuery.
Second, the program interface:
3. Toolkit code:
function Snapcat(paper,data,options){ this.options={ centerX:100, centerY:100, bigRadius:70, smallRadius:40, leafClickHandler:function(json){ alert("id="+json.id+", data="+json.data); }, colors:["#fa3e3e","#fa9c3e","#fafa3e","#9cfa3e","#3efa3e","#3efa9c","#3efafa","#3e9cfa","#3e3efa","#9c3efa"] }; if(options){ jQuery.extend(this.options,options); } this.paper = paper; this.data = data; var exitPathDef = "M"+this.options.centerX+","+this.options.centerY+" Q"+this.options.centerX+" 0,0 0"; var enterPathDef="M0 0,Q0 "+this.options.centerY+","+this.options.centerX+" "+this.options.centerY; //Exit path, internal variable this.exitPath = paper.path(exitPathDef).attr({fill:'none'}); // make path, internal variable this.enterPath = paper.path(enterPathDef).attr({fill:'none'}); this.getLevelColor=function(level){ if(level>=this.options.colors.length)return "#f00"; else return this.options.colors[level]; }; // get data by ID this.getDataById=function (id){ for(var i=0; i<this.data.length; i++){ if(this.data[i].id==id)return this.data[i]; } return null; }; this.getDataByPid=function(id){ var result = []; for(var i=0; i<this.data.length; i++){ if(this.data[i].pid==id)result.push(this.data[i]); } return result; }; this.getLevel=function(id){ var level = 0; var data = this.getDataById(id); if(!data)return level; while(data.pid!=0){ level++; data = this.getDataById(data.pid); } return level; }; //Internal private function function drawMainCat(cx,cy,r,id,millisec){ var result = {}; var data = this.getDataById(id); var level = this.getLevel(id); result.circle=this.paper.circle(cx,cy,r).attr({ fill:this.getLevelColor(level), stroke:this.getLevelColor(level), strokeOpacity:0.75, r:0, "data-id":data.id, "data-pid":data.pid, strokeWidth:8 }); result.text = paper.text(cx,cy,data.label) .attr({"opacity":0,"data-id":data.id,"data-pid":data.pid}); var bbox = result.text.getBBox (); var matrix = new Snap.Matrix(); matrix.translate(-bbox.width/2, bbox.height/2); result.text.transform(matrix); if(millisec){ result.circle.animate({r:r},millisec*9/10,mina.bounce,function(){ result.text.animate({opacity:1},millisec/10,mina.bounce,function(){ }); }); } else{ result.circle.attr({r:r}); result.text.attr({opacity:1}); } return result; } // draw subclass function drawSubCat(cx,cy,r1,r2,id,timeOutMillisec,dualMillisec){ var self = this; // used in inner functions // show subclasses var data = this.getDataByPid(id); var level = this.getLevel(id); if(!data || data.length==0)return; var x, y; var distance = r1 + r2 + 10; var subcircles = this.paper.group(); var subcircle,subtext,matrix; var datalen = data.length; var result = []; for (var i = 0; i <datalen; i ++) { x = distance*Math.sin(360*i*Math.PI/180/datalen)+this.options.centerX; y = distance*Math.cos(360*i*Math.PI/180/datalen)+this.options.centerY; subcircle=paper.circle(x,y,0).attr({"data-id":data[i].id,"data-pid":data[i].pid,"data-idx":i,"data-data":data[i].data}); subcircles.add(subcircle); subtext = paper.text(x,y,data[i].label).attr({"data-id":data[i].id,"data-pid":data[i].pid,"data-data":data[i].data,opacity:0,"data-idx":i}); bbox = subtext.getBBox(); matrix = new Snap.Matrix(); matrix.translate(-bbox.width/2,bbox.height/2); subtext.transform(matrix); result.push({circle:subcircle,text:subtext}); } subcircles.attr({ fill:this.getLevelColor(level+1), stroke:this.getLevelColor(level+1), strokeOpacity:0.75, strokeWidth:8 }); if(timeOutMillisec && dualMillisec){ setTimeout(function(){ var circle,text; for (var i = 0; i <datalen; i ++) { Snap($("circle[data-id="+data[i].id+"]")[0]).animate({r:r2},dualMillisec*9/10,mina.bounce,function(){ var id = this.node.getAttribute("data-id"); Snap($("text[data-id="+id+"]")[0]).animate({opacity:1},dualMillisec/10,mina.bounce); }); } },timeOutMillisec); } else{ for (var i = 0; i <datalen; i ++) { Snap($("circle[data-id="+data[i].id+"]")[0]).attr({r:r2}); Snap($("text[data-id="+data[i].id+"]")[0]).attr({opacity:1}); } } //set event var clickHandler = function(){ var idx = this.node.getAttribute("data-idx"); var pid = this.node.getAttribute("data-pid"); var id = this.node.getAttribute("data-id"); var catdata = this.node.getAttribute("data-data"); if(self.getDataByPid(id).length==0){ self.options.leafClickHandler({id:id,data:catdata}); return; } $("circle[data-idx!="+idx+"][data-pid="+pid+"]").remove(); $("text[data-idx!="+idx+"][data-pid="+pid+"]").remove(); //paper.selectAll("circle[data-id="+pid+"],text[data-id="+pid+"]").remove(); var length = Snap.path.getTotalLength(self.exitPath); var circle = Snap($("circle[data-id="+pid+"]")[0]); var text = Snap($("text[data-id="+pid+"]")[0]); // remove the big circle Snap.animate(0,length,function(val){ var point = Snap.path.getPointAtLength(self.exitPath,val); circle.attr({cx:point.x,cy:point.y}); text.attr({x:point.x,y:point.y}); },timeOutMillisec,mina.easeout); //After moving to the upper left corner, add an event, responsible for moving back to the big circle circle.click(function(){ var id = this.node.getAttribute("data-id"); $("circle[data-id!="+id+"]").remove(); $("text[data-id!="+id+"]").remove(); var length = Snap.path.getTotalLength(self.enterPath); var circle=Snap($('circle[data-id='+id+']')[0]); var text=Snap($('text[data-id='+id+']')[0]); //move back to the big circle Snap.animate(0,length, function(val){ var point = Snap.path.getPointAtLength(self.enterPath,val); circle.attr({cx:point.x,cy:point.y}); text.attr({x:point.x,y:point.y}); }, timeOutMillisec, function(){ circle.unclick(); }); drawSubCat.bind(self)(cx,cy,r1,r2,id,timeOutMillisec,dualMillisec); }); var subCircle = Snap($("circle[data-id="+id+"]")[0]) ; var subText = Snap($("text[data-id="+id+"]")[0]) ; var subPathDef = "M"+subCircle.attr("cx")+" "+subCircle.attr("cy")+" L"+self.options.centerX+" "+self.options.centerY; var subPath = paper.path(subPathDef); length = Snap.path.getTotalLength(subPath); // enlarge the small circle Snap.animate(self.options.smallRadius,self.options.bigRadius, function(val){ subCircle.attr({r:val}); }, dualMillisec,mina.easeout ); subText.unclick(); subCircle.unclick(); // move the circle to the center Snap.animate(0,length,function(val){ var point = Snap.path.getPointAtLength(subPath,val); subCircle.attr({cx:point.x,cy:point.y}); subText.attr({x:point.x,y:point.y}); }, dualMillisec,mina.easeout, function(){ drawSubCat.bind(self)(cx,cy,r1,r2,id,dualMillisec,dualMillisec); } ); };//end of click event for(var i=0; i<result.length;i++){ result[i].text.click(clickHandler); result[i].circle.click(clickHandler); }//end of for return result; } this.drawCat=function(){ var millsec = 600; drawMainCat.bind(this)(this.options.centerX,this.options.centerY,this.options.bigRadius,1,millsec); drawSubCat.bind(this)(this.options.centerX,this.options.centerY,this.options.bigRadius,this.options.smallRadius,1,millsec,400); } }//end of Snapcat
Fourth, the application example:
<!DOCTYPE html> <!-- Author: wallimn, http://wallimn.iteye.com When: May 7, 2017 Function: Cool classified animation display package --> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <title>Cool category-wallimn</title> <style type="text/css"> html,body{ width:100%; height:100%; } #svg { margin:0; position:relative; top:50%; border-radius:5px; border:1px solid #efefef; } text{ font-size:14px; } </style> </head> <body> <svg id='paper'></svg> <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="js/snap.svg-min.js"></script> <script type="text/javascript" src="js/snapcat.js"></script> <script type="text/javascript"> $(function(){ var clientWidth=document.body.clientWidth; var clientHeight=document.body.clientHeight; $("#paper").css("width",clientWidth+"px").css("height",clientHeight+"px"); var minsize = Math.min(clientWidth,clientHeight); var paper = Snap("#paper"); //Create a circle with a bed radius of 80 var centerX=clientWidth/2, centerY=clientHeight/2 ; var data = [ {id:1,pid:0,label:'knowledge body',data:null}, {id:2,pid:1,label:'Product',data:null}, {id:3,pid:1,label:'operation',data:null}, {id:4,pid:1,label:'planning',data:null}, {id:5,pid:1,label:'Creative',data:null}, {id:6,pid:1,label:'Strategy',data:null}, {id:9,pid:2,label:'Product-Subclass 1',data:'A001'}, {id:10,pid:2,label:'Product-Subclass 2',data:'A002'}, {id:31,pid:2,label:'Product-Subclass 3',data:'A001'}, {id:32,pid:2,label:'Product-Subclass 4',data:'A002'}, {id:11,pid:3,label:'Operation-Subclass 1',data:'A003'}, {id:12,pid:3,label:'Operation-Subclass 2',data:'A004'}, {id:13,pid:3,label:'Operation-Subclass 3',data:'A005'}, {id:14,pid:4,label:'planning-subclass 1',data:'A006'}, {id:15,pid:4,label:'planning-subclass 2',data:'A007'}, {id:16,pid:4,label:'planning-subclass 3',data:'A008'}, {id:17,pid:4,label:'planning-subclass 4',data:'A009'}, {id:18,pid:5,label:'Creativity-Subclass 1',data:'A010'}, {id:18,pid:5,label:'Creativity-Subclass 2',data:'A011'}, {id:20,pid:6,label:'Strategy-Subclass 1',data:'A012'}, {id:21,pid:6,label:'Strategy-Subclass 2',data:'A013'}, {id:22,pid:6,label:'Strategy-Subclass 3',data:'A014'}, {id:23,pid:6,label:'Strategy-Subclass 4',data:'A012'}, {id:24,pid:6,label:'Strategy-Subclass 5',data:'A013'}, {id:25,pid:6,label:'Strategy-Subclass 6',data:'A014'}, ]; var snapcat = new Snapcat(paper,data,{centerX:centerX,centerY:centerY}); snapcat.drawCat(); }); </script> </body> </html>
5. Code warehouse:
Upload the code to github.com, visit the address: https://github.com/wallimn/snapcat , and download all the programs by pressing the button.
For mobile phone experience, please use WeChat to scan the following QR code, no attention, no registration, and no download required: