commit 926b0cfc28f658c59296b69fde599dc9daf3cb9d
Author: shye0000 <shye0000@gmail.com>
Date:   Mon Sep 14 16:41:07 2015 +0200

    Module dataset Explorer D3

diff --git a/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3.js b/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3.js
new file mode 100644
index 0000000..ecd99e1
--- /dev/null
+++ b/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3.js
@@ -0,0 +1,29 @@
+Ext.namespace('sitools.user.modules');
+
+Ext.define( 'sitools.user.modules.DatasetExplorerD3', {
+    extend: 'sitools.user.core.Module',
+
+
+    init : function (moduleModel) {
+        var view = Ext.create('sitools.user.view.modules.datasetExplorerD3.DatasetExplorerD3');
+        this.setViewCmp(view);
+
+        this.show(this.getViewCmp());
+
+        this.callParent(arguments);
+    },
+
+    /**
+     * method called when trying to save preference
+     * 
+     * @returns
+     */
+    _getSettings : function () {
+        return {
+            preferencesPath : "/modules",
+            preferencesFileName : this.id
+        };
+
+    }
+
+});
\ No newline at end of file
diff --git a/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3View.js b/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3View.js
new file mode 100644
index 0000000..39e54c8
--- /dev/null
+++ b/Module_DatasetExplorerD3_sitools2v3/DatasetExplorerD3View.js
@@ -0,0 +1,442 @@
+Ext.namespace('sitools.user.view.modules.datasetExplorerD3');
+/**
+ * ProjectDescription Module
+ * @class sitools.user.modules.projectDescription
+ * @extends Ext.Panel
+ */
+Ext.define('sitools.user.view.modules.datasetExplorerD3.DatasetExplorerD3', {
+    extend : 'Ext.panel.Panel',
+    layout : 'fit',
+    id : 'ds',
+    border : false,
+    bodyBorder : false,
+    listeners: {
+        //afterrender:function(){console.log( 'afterrender ' +this.getHeight())},
+        boxready: function() {
+            //alert(this.getHeight()+' '+this.getWidth());
+            var me = this;
+            //me.doc = Ext.getDoc();
+            //me.callParent(arguments);
+            me.drawMap();
+                 },
+        resize: function() {
+            //alert(this.getHeight()+' '+this.getWidth());
+            var me = this;
+            d3.select("#vis").remove();
+            //me.doc = Ext.getDoc();
+            //me.callParent(arguments);
+            me.drawMap();
+        }
+    },
+    initComponent : function () {
+        this.callParent(arguments);
+
+    },
+
+    drawMap : function() {
+        if (Math.min(this.getHeight(),this.getWidth()) < 400) var fontSize = '0px';
+        else if (Math.min(this.getHeight(),this.getWidth()) > 800) var fontSize = '14px';
+        else var fontSize = (Math.round(Math.min(this.getHeight(),this.getWidth()).toFixed(1)/100)+Math.floor(Math.min(this.getHeight(),this.getWidth()).toFixed(1)/100)-2).toString()+'px';
+
+        me = this;
+        var project = Ext.getStore('ProjectStore').getProject();
+        var d = document,
+            g = d.getElementById('ds');
+        if (this.getHeight() > this.getWidth()) {
+        var width = this.getWidth()/1.02,
+            height = width;
+        } else {
+            var height = this.getHeight()/1.05 ,
+            width = height;
+        }
+        function t(n, e) {
+            return n === e ? !0 : n.children ? n.children.some(function(n) {
+                return t(n, e)
+            }) : !1
+        }
+
+        function n(t) {
+            if (t.children) {
+                var e = t.children.map(n),
+                r = d3.hsl(e[0]),
+                a = d3.hsl(e[1]);
+                return d3.hsl((r.h + a.h) / 2, 1.2 * r.s, r.l / 1.2)
+            }
+            return t.colour || "#fff"
+        }
+
+        function e(t) {
+            var n = r(t),
+                e = d3.interpolate(d.domain(), [t.x, t.x + t.dx]),
+                a = d3.interpolate(u.domain(), [t.y, n]),
+                i = d3.interpolate(u.range(), [t.y ? 20 : 0, o]);
+            return function(t) {
+                return function(n) {
+                        return d.domain(e(n)), u.domain(a(n)).range(i(n)), x(t)
+                }
+            }
+        }
+
+        function r(t) {
+            return t.children ? Math.max.apply(Math, t.children.map(r)) : t.y + t.dy
+        }
+
+        function a(t) {
+            return .299 * t.r + .587 * t.g + .114 * t.b
+        }
+        var radius = width / 2,
+            x = d3.scale.linear().range([0, 2 * Math.PI]),
+            y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, radius]),
+            padding = 5,
+            duration = 500;
+
+        var color = d3.scale.category20c();
+
+        var ds = d3.select("#ds");
+        var div = ds.append("div").attr("id","vis");
+        var vis = div.append("svg")
+            .attr("width", width + padding * 2)
+            .attr("height", height + padding * 2)
+            .append("g")
+            .attr("id", "container")
+            .attr("transform", "translate(" + [radius + padding, radius + padding] + ")");
+        var partition = d3.layout.partition()
+            .sort(null)
+            .value(function(d) {
+                //console.log(Math.sqrt(d.nbRecord));
+                return 5.8-d.depth;
+            });
+
+        var arc = d3.svg.arc()
+            .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
+            .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
+            .innerRadius(function(d) { return Math.max(0, d.y ? y(d.y) : d.y); })
+            .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
+        //d3.json("graph.json", function(error, json) {
+        d3.json(project.get('sitoolsAttachementForUsers')+"/graph?media=json", function(error, json) {
+            d3.select("#container").on("mouseleave", mouseleave);
+            //d3.select("#container").on("touchend", mouseleave);
+            json.graph.text = 'Solar';
+            json.graph.children = json.graph.nodeList;
+            var nodes = partition.nodes({children: json.graph.children[0].children})
+            /*.filter(function(d) {
+                return (d.dx > 0.05); // 0.005 radians = 0.29 degrees
+            })*/;
+            var path = vis.selectAll("path").data(nodes);
+            var pathEnter = path.enter().append("path")
+            .attr("id", function(d, i) { return "path-" + i; })
+            .attr("class", "pathSolarProject")
+            .attr("d", arc)
+            .attr("fill-rule", "evenodd")
+            .style("fill", function(d, i) { if (i==0) return d.color = '#FDB813'; else return d.color = color((d.children ? d : d.parent).text);})
+            .on("mouseover", mouseover)
+            //.on("touchenter", mouseover)
+            //.on("touchstart", mouseover)
+            .on("click", click);
+            var tooltips= pathEnter
+                .append("title")
+                .text(function(d, i) { if (i != 0) return d.description? d.description : d.text.split('<br/>')[0]; });
+
+            var text = vis.selectAll("text").data(nodes);
+            var textEnter = text.enter().append("text")
+                .attr("class", "pathSolarProject")
+                .style("fill-opacity", 1)
+                .style("fill", function(d) {
+                    return brightness(d3.rgb(d.color)) < 125 ? "#fff" : "#000";
+                })
+                .attr("text-anchor", function(d, i) {
+                    if (i == 0) {
+                        return "middle";
+                    }
+                    return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
+                })
+                .attr("dy", ".3em")
+                .attr("dx", function(d, i){
+                    if (i == 0) return 0;
+                    return x(d.x + d.dx / 2) > Math.PI ? "-1.5em" : "1.5em";
+                })
+                .attr("transform", function(d, i) {
+                    if (i == 0) {
+                        return null;
+                    }
+                    var multiline = (d.text || "").split(" ").length > 1,
+                    angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
+                    rotate = angle + (multiline ? -.5 : 0);
+                    return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
+                })
+                .on("click", click);
+            textEnter.append("title")
+                .attr("class", "pathSolarProject")
+                .text(function(d, i) { if (i != 0) return d.description? d.description : d.text.split('<br/>')[0]; });
+            var image = vis.selectAll("image").data(nodes);
+            imageEnter = image.enter().append("image")
+                .attr("class","dataIconImg pathSolarProject")
+                .attr("xlink:href",function(d, i){
+                    if (i == 0) return "";
+                    else {
+                        if (d.type == "node") {
+                            if (d.text.search("Query form") > -1)
+                                return brightness(d3.rgb(d.color)) < 125 ? "/sitools/upload/search-white.png" : "/sitools/upload/search-black.png";
+                            else if (d.text.search("Display data") > -1)
+                                return brightness(d3.rgb(d.color)) < 125 ? "/sitools/upload/database-white.png" : "/sitools/upload/database-black.png";
+                            else
+                                return "";
+                        }
+                        else return brightness(d3.rgb(d.color)) < 125 ? "/sitools/upload/database-white.png" : "/sitools/upload/database-black.png";
+                    }
+                })
+                .attr('width', "1em")
+                .attr('height', "1em")
+                .style("fill-opacity", 1)
+                .style("fill", function(d) {
+                    return brightness(d3.rgb(d.color)) < 125 ? "#fff" : "#000";
+                })
+                .style('cursor','pointer')
+                .attr("y", "-0.5em")
+                .attr("x", function(d){
+                    return x(d.x + d.dx / 2) > Math.PI ? "-1.2em" : "0.2em";
+                })
+                .attr("transform", function(d, i) {
+                    if (i == 0) {
+                        return null;
+                    }
+                    var multiline = (d.text || "").split(" ").length > 1,
+                    angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
+                    rotate = angle + (multiline ? -.5 : 0);
+                    return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
+                })
+                .on("click", function(d,i) {
+                    if (i == 0){
+                        return false;
+                    }
+                    if (d.type == "node" && (d.text.search("Query form")>-1))
+                        sitools.user.utils.DatasetUtils.clickDatasetIcone(d.text.split("clickDatasetIcone('")[1].split(", 'forms'")[0], 'forms');
+                    if (d.type == "node" && (d.text.search("Display data")>-1))
+                        sitools.user.utils.DatasetUtils.clickDatasetIcone(d.text.split("clickDatasetIcone('")[1].split("', 'data'")[0], 'data');
+                    if (d.type == "dataset")
+                        sitools.user.utils.DatasetUtils.clickDatasetIcone(d.url, 'data');
+                    return false;
+                })
+                .on("mouseover", iconhover);
+            function iconhover(d,i) {
+                imageEnter.attr("width", function(e){
+                        if (d.text == e.text) {
+                            return "1.1em";
+                        } else {
+                            return "1em";
+                        }
+                    })
+                    .attr("height", function(e){
+                        if (d.text == e.text) {
+                            return "1.1em";
+                        } else {
+                            return "1em";
+                        }
+                    });
+            }
+            image.append("svg:title")
+                .text(function(d, i) {
+                  if (i == 0) return "";
+                    else {
+                        if (d.type == "node") {
+                            if (d.text.search("Query form") > -1)
+                                return "Query form";
+                            else if (d.text.search("Display data") > -1)
+                                return "Display data";
+                            else
+                                return "";
+                        }
+                        else return "Display data";
+                    }
+            });
+            if (Math.min(me.getHeight(), me.getWidth()) >= 400){
+                var tspan = textEnter.append("tspan")
+                    .attr("x", 0)
+                    .style("font-weight", function(d, i) { return i == 0 ? "bold" : ""; })
+                    .style("font-size", function(d, i) { return fontSize; })
+                    .text(function(d, i) { if (i == 0) { return 'SOLAR'; } return d.depth ? d.text.split("<br/>")[0] : ""; });
+            }
+            function click(d) {
+                d3.select("#container").on("mouseleave", null);
+                d3.selectAll(".pathSolarProject").on("mouseover", null);
+                path.transition()
+                    .duration(duration)
+                    .attrTween("d", arcTween(d));
+                    d3.selectAll(".pathSolarProject")
+                    .style("opacity", 1);
+                setTimeout(function(){
+                    d3.select("#container").on("mouseleave", mouseleave);
+                    d3.selectAll(".pathSolarProject").on("mouseover", mouseover);
+                        //.on("touchstart", mouseover)
+                        //.on("touchenter", mouseover);
+                }, duration);
+
+                // Somewhat of a hack as we rely on arcTween updating the scales.
+                text.style("visibility", function(e) {
+                    return isParentOf(d, e) ? null : d3.select(this).style("visibility");
+                })
+                    .transition()
+                    .duration(duration)
+                    .attrTween("text-anchor", function(d, i) {
+                        if (i == 0) {
+                            return null;
+                        }
+                        return function() {
+                            return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
+                        };
+                    })
+                    .attr("dx", function(d, i){
+                        if (i == 0) return 0;
+                        else return x(d.x + d.dx / 2) > Math.PI ? "-1.5em" : "1.5em";
+                    })
+                    .attrTween("transform", function(d, i) {
+                        if (i == 0) {
+                            return null;
+                        }
+                        var multiline = (d.text || "").split(" ").length > 1;
+                        return function() {
+                            var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
+                            rotate = angle + (multiline ? -.5 : 0);
+                            return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
+                        };
+                    })
+                    .style("fill-opacity", function(e) { return isParentOf(d, e) ? 1 : 1e-6; })
+                    .each("end", function(e) {
+                        d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
+                    });
+                setTimeout(function(){
+                    text.attr("dx", function(d, i){
+                        if (i == 0) return 0;
+                        else return x(d.x + d.dx / 2) > Math.PI ? "-1.5em" : "1.5em";
+                    });
+                }, duration+20);
+                image.style("visibility", function(e) {
+                    return isParentOf(d, e) ? null : d3.select(this).style("visibility");
+                })
+                    .transition()
+                    .duration(duration)
+                    .attr("y", "-0.5em")
+                    .attr("x", function(d){
+                        return x(d.x + d.dx / 2) > Math.PI ? "-1.2em" : "0.2em";
+                    })
+                    .attrTween("transform", function(d, i) {
+                        if (i == 0) {
+                            return null;
+                        }
+                        var multiline = (d.text || "").split(" ").length > 1;
+                        return function() {
+                            var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
+                            rotate = angle + (multiline ? -.5 : 0);
+                            return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
+                        };
+                    })
+                    .style("fill-opacity", function(e) { return isParentOf(d, e) ? 1 : 1e-6; })
+                    .each("end", function(e) {
+                        d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
+                    });
+                setTimeout(function(){
+                    image.attr("x", function(d){
+                        return x(d.x + d.dx / 2) > Math.PI ? "-1.2em" : "0.2em";;
+                    });
+                }, duration+20);
+            }
+            function mouseleave(d) {
+                // Hide the breadcrumb trail
+                //d3.select("#trail")
+                //  .style("visibility", "hidden");
+
+                // Deactivate all segments during transition.
+                d3.selectAll(".pathSolarProject").on("mouseover", null);
+
+                // Transition each segment to full opacity and then reactivate it.
+                d3.selectAll(".pathSolarProject")
+                    .transition()
+                    .duration(500)
+                    .style("opacity", 1)
+                    .each("end", function() {
+                        d3.select(this).on("mouseover", mouseover);
+                        //d3.select(this).on("touchstart", mouseover);
+                        //d3.select(this).on("touchenter", mouseover);
+                    });
+            }
+
+            function mouseover(d) {
+                var sequenceArray = getAncestors(d);
+                //updateBreadcrumbs(sequenceArray, percentageString);
+
+                // Fade all the segments.
+                d3.selectAll(".pathSolarProject")
+                    .style("opacity", 0.4);
+                // Then highlight only those that are an ancestor of the current segment.
+                vis.selectAll(".pathSolarProject")
+                    .filter(function(node) {
+                        return (sequenceArray.indexOf(node) >= 0);
+                    })
+                    .style("opacity", 1);
+                vis.selectAll("text")
+                    .filter(function(node) {
+                        return (sequenceArray.indexOf(node) >= 0);
+                    })
+                    .style("opacity", 1);
+                vis.selectAll("image")
+                    .filter(function(node) {
+                        return (sequenceArray.indexOf(node) >= 0);
+                    })
+                    .style("opacity", 1);
+            }
+            function isParentOf(p, c) {
+                if (p === c) return true;
+                if (p.children) {
+                    return p.children.some(function(d) {
+                        return isParentOf(d, c);
+                    });
+                }
+                return false;
+            }
+
+            function getAncestors(node) {
+                var path = [];
+                var current = node;
+                while (current.parent) {
+                    path.unshift(current);
+                    current = current.parent;
+                }
+                path.unshift(current);
+                return path;
+            }
+
+            // Interpolate the scales!
+            function arcTween(d) {
+                var my = maxY(d),
+                    xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
+                    yd = d3.interpolate(y.domain(), [d.y, my]),
+                    yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
+                return function(d) {
+                    return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
+                };
+            }
+
+            function maxY(d) {
+                return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;
+            }
+
+            // http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
+            function brightness(rgb) {
+                return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;
+            }
+
+        });
+    },
+    /**
+     * method called when trying to save preference
+     * @returns
+     */
+    _getSettings : function () {
+        return {
+            preferencesPath : "/modules",
+            preferencesFileName : this.id,
+            xtype : this.$className
+        };
+
+    }
+});
diff --git a/Module_DatasetExplorerD3_sitools2v3/style.css b/Module_DatasetExplorerD3_sitools2v3/style.css
new file mode 100644
index 0000000..de2968c
--- /dev/null
+++ b/Module_DatasetExplorerD3_sitools2v3/style.css
@@ -0,0 +1,20 @@
+svg {
+	position: absolute;
+	top: 10px;
+	left: 0;
+	right: 0;
+	margin-left: auto;
+	margin-right: auto;
+}
+path {
+    cursor: pointer;
+    stroke: #fff;
+    stroke-width: 1;
+}
+text {
+    cursor: pointer;
+    font-family: Arial, Helvetica, sans-serif;
+}
+#vis {
+  border-radius: 50%;
+}
