Custom visual example -- using Custom Style (JS)

Using Custom Style it’s possible to take existing D3 visuals and use them within Arcadia.

Note: This feature requires reasonable knowledge of javascript and d3 library.

As an example, refer to this D3 pie chart:

You can manipulate the D3 pie chart to work within Arcadia. The JS at the bottom of this post contain D3 pie chart javascript that has been edited to work within Arcadia. You can copy & paste the JS and insert it directly into a custom style as shown here:

Read more about custom styles here: http://documentation.arcadiadata.com/4.3.0.0/#pages/topics/custom-style-site-wide-define-js.html

Then you can apply this custom style to a tabular visual to get the custom visual

— CUSTOM STYLE CODE—

 return function() {
       var f = function() {};
        f.version = "1";
    f.settings = function() {
        return [
            {id: 'height', defaultValue: '100'},
            {id: 'radius', defaultValue: '200'},
            {
                id: 'donut arc width(0 will show as Pie chart)', defaultValue: '0'
            },
            {id: 'Decimals included in percentage', defaultValue: '2'},
            {id: 'Show Percentages on Marks', defaultValue: ''},
            {id: 'Legend font size', defaultValue: '10px'},
        ];
    };

    f.disableDraw = function() {
        return true;
    };

    f.beforeDraw = function () {
        if (document.getElementById('col-sm-12')) {
            d3.selectAll("#col-sm-12").remove();
        }        

        if (document.getElementById('canvas')) {
            d3.selectAll("#canvas").remove();
        }

        return ;
    };

    f.afterDraw = function() {
        var pieHeight = arcapi.getSetting('height');
        var radius = arcapi.getSetting('radius');
        var arcwidth = parseFloat(arcapi.getSetting('donut arc width(0 will show as Pie chart)'));
        var percent = arcapi.getSetting('Decimals included in percentage');
        var showpercent = arcapi.getSetting('Show Percentages on Marks');
        var showmarks = arcapi.getSetting('Show Dimensions on Marks');
        var legendfsize = arcapi.getSetting('Legend font size');

        var padding = 20;
        var lib = arcapi.unsupportedDriver;

        var $viz = $('#' + arcapi.chartId());
        var height = $viz.height(),
            width = $viz.width();

        var d = arcapi.dataResult();
        var allRows = d.rows();
        var dCols = arcapi.dataResult().colNames;
        var columns = d.columns(); // all data columns
        var pieradius = 0;
        var colors = arcapi.unsupportedDriver.colors();
        var colorScale = arc.misc.dimensionColorScale();
        colorScale.range(colors);

        var legendRectSize = 18;
        var legendSpacing = 4;

        if (document.getElementById('canvas')) {
            d3.selectAll("#canvas").remove();
        }

         var svg = d3.select("#"+arcapi.chartId()).append("svg")
            .attr("id", "canvas")
            .attr("width", width)
            .attr("height", height);

        console.log("keys" + allRows[0]);
  
        function loadData(){
        	return allRows.map(function(d){ 
        		return {label:d[0], value:d[1], color: colorScale(d[0]) };});
        }
 
       function dimList(){
        	return allRows.map(function(d){ 
        		return d[0]});
        }

        var d3d = svg.append("g").attr("id","3dDonut");
        
        if( width > height) { pieradius = height/2 } else { pieradius = width/2}
        
        Donut3D.draw(d3d, loadData(), width/2-padding, height/2-padding, pieradius-padding, pieradius-parseInt(pieHeight), parseInt(pieHeight), arcwidth);

        console.log("dimlist" + dimList().length);
       
        var legend = svg.selectAll('.legend')
          .data(dimList())
          .enter()
          .append('g')
          .attr('class', 'legend')
          .attr('transform', function(d, i) {
            var lheight = legendRectSize + legendSpacing;
            var offset =  lheight * dimList().length /10 ;
            var horz = width -6 * legendRectSize;
            var vert = i * lheight ;
            
            return 'translate(' + horz + ',' + vert + ')';
          });
 
        legend.append('rect')
          .attr('width', legendRectSize)
          .attr('height', legendRectSize)
          .style('fill', function(d){return colorScale(d)})
          .style('stroke', function(d){return colorScale(d)});

        legend.append('text')
          .attr('x', legendRectSize + legendSpacing)
          .attr('y', legendRectSize - legendSpacing)
          .style("font-size", legendfsize)
          .text(function(d) { return d; });
    };

    !function(){
    	var Donut3D={};
    	
    	function pieTop(d, rx, ry, ir ){
    		if(d.endAngle - d.startAngle === 0 ) return "M 0 0";
    		var sx = rx*Math.cos(d.startAngle),
    			sy = ry*Math.sin(d.startAngle),
    			ex = rx*Math.cos(d.endAngle),
    			ey = ry*Math.sin(d.endAngle);

    		var ret =[];
    		ret.push("M",sx,sy,"A",rx,ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0),"1",ex,ey,"L",ir*ex,ir*ey);
    		ret.push("A",ir*rx,ir*ry,"0",(d.endAngle-d.startAngle > Math.PI? 1: 0), "0",ir*sx,ir*sy,"z");
    		return ret.join(" ");
    	}
    
    	function pieOuter(d, rx, ry, h ){
    		var startAngle = (d.startAngle > Math.PI ? Math.PI : d.startAngle);
    		var endAngle = (d.endAngle > Math.PI ? Math.PI : d.endAngle);
    		
    		var sx = rx*Math.cos(startAngle),
    			sy = ry*Math.sin(startAngle),
    			ex = rx*Math.cos(endAngle),
    			ey = ry*Math.sin(endAngle);
    			
    			var ret =[];
    			ret.push("M",sx,h+sy,"A",rx,ry,"0 0 1",ex,h+ey,"L",ex,ey,"A",rx,ry,"0 0 0",sx,sy,"z");
    			return ret.join(" ");
    	}

    	function pieInner(d, rx, ry, h, ir ){
    		var startAngle = (d.startAngle < Math.PI ? Math.PI : d.startAngle);
    		var endAngle = (d.endAngle < Math.PI ? Math.PI : d.endAngle);
    		
    		var sx = ir*rx*Math.cos(startAngle),
    			sy = ir*ry*Math.sin(startAngle),
    			ex = ir*rx*Math.cos(endAngle),
    			ey = ir*ry*Math.sin(endAngle);
    
    			var ret =[];
    			ret.push("M",sx, sy,"A",ir*rx,ir*ry,"0 0 1",ex,ey, "L",ex,h+ey,"A",ir*rx, ir*ry,"0 0 0",sx,h+sy,"z");
    			return ret.join(" ");
    	}
    
    	function getPercent(d){
    		return (d.endAngle-d.startAngle > 0.2 ? 
    				Math.round(1000*(d.endAngle-d.startAngle)/(Math.PI*2))/10+'%' : '');
    	}	
    	
    	Donut3D.transition = function(did, data, rx, ry, h, ir){
    		function arcTweenInner(a) {
    		  var i = d3.interpolate(this._current, a);
    		  this._current = i(0);
    		  return function(t) { return pieInner(i(t), rx+0.5, ry+0.5, h, ir);  };
    		}
    		function arcTweenTop(a) {
    		  var i = d3.interpolate(this._current, a);
    		  this._current = i(0);
    		  return function(t) { return pieTop(i(t), rx, ry, ir);  };
    		}
    		function arcTweenOuter(a) {
    		  var i = d3.interpolate(this._current, a);
    		  this._current = i(0);
    		  return function(t) { return pieOuter(i(t), rx-0.5, ry-0.5, h);  };
    		}
    		function textTweenX(a) {
    		  var i = d3.interpolate(this._current, a);
    		  this._current = i(0);
    		  return function(t) { return 0.6*rx*Math.cos(0.5*(i(t).startAngle+i(t).endAngle));  };
    		}
    		function textTweenY(a) {
    		  var i = d3.interpolate(this._current, a);
    		  this._current = i(0);
    		  return function(t) { return 0.6*rx*Math.sin(0.5*(i(t).startAngle+i(t).endAngle));  };
    		}

    		var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
    		
    		did.selectAll(".innerSlice").data(_data)
    			.transition().duration(750).attrTween("d", arcTweenInner); 
    			
    		did.selectAll(".topSlice").data(_data)
    			.transition().duration(750).attrTween("d", arcTweenTop); 
    			
    		did.selectAll(".outerSlice").data(_data)
    			.transition().duration(750).attrTween("d", arcTweenOuter); 	
    			
    		did.selectAll(".percent").data(_data).transition().duration(750)
    			.attrTween("x",textTweenX).attrTween("y",textTweenY).text(getPercent); 	
    	};
  
        var mouseclick_slice = function(z){ 
                var lib = arcapi.unsupportedDriver;
                var d = arcapi.dataResult();
                var params = {};
                var columns = d.columns(); // all data columns

                var dim1 = columns[0].colname();
                var dimval1 = z;
                
                 function whereClause(col, val) {
                    return col + "='" + val + "'";
                }
            
                console.log("dim1:" + dim1);
                console.log("dimval1:" + dimval1);
                
                function joinClauses(parts, joiner) {
                    return '(' + parts.join(') ' + joiner + ' (') + ')';
                }

                params[dim1] = dimval1;

                var and1 = [whereClause(dim1, dimval1)];

                params.whereclause = and1;
                console.log("params:" + params.whereclause);

                arcapi.sendParameters(params);
        }; 

    	Donut3D.draw=function(gid, data, x /*center x*/, y/*center y*/, 
    			rx/*radius x*/, ry/*radius y*/, h/*height*/, ir/*inner radius*/){
 
            var lib = arcapi.unsupportedDriver;
            var d = arcapi.dataResult();
            var params = {};
            var columns = d.columns(); // all data columns
            var legendfsize = arcapi.getSetting('Legend font size');

    		var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);
    		
    		var slices = gid.append("g").attr("transform", "translate(" + x + "," + y + ")")
    			.attr("class", "slices");

    		slices.selectAll(".innerSlice").data(_data).enter().append("path").attr("class", "innerSlice")
    			.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); })
    			.on("click",function(d) { mouseclick_slice(d.data.label); })
    			.attr("d",function(d){ return pieInner(d, rx+0.5,ry+0.5, h, ir);})
    			.each(function(d){this._current=d;});

    		slices.selectAll(".topSlice").data(_data).enter().append("path").attr("class", "topSlice")
    			.style("fill", function(d) { return d.data.color; })
    			.style("stroke", function(d) { return d.data.color; })
    			.on("click",function(d) { mouseclick_slice(d.data.label); })
    			.on("mouseover",function(d) { mouseover_slice(d); })
    			.attr("d",function(d){ return pieTop(d, rx, ry, ir);})
    			.transition().duration(750)
    			.each(function(d){this._current=d;});

    		slices.selectAll(".outerSlice").data(_data).enter().append("path").attr("class", "outerSlice")
    			.style("fill", function(d) { return d3.hsl(d.data.color).darker(0.7); })
    			.on("click",function(d) { mouseclick_slice(d.data.label); })
    			.attr("d",function(d){ return pieOuter(d, rx-0.5,ry-0.5, h);})
    			.each(function(d){this._current=d;});

            var tslices = d3.selectAll(".topSlice");
            var tooltip =
                arc.tooltip()
               .dom_id('#tooltip')
               .text_fn(function(d) {
                    return lib.tooltip_from_kvs([
                       {
                           key: columns[0].colname(),
                           value: d.data.label,
                       },
                       {
                           key: columns[1].colname(),
                           value: d.data.value,
                       },
                   ]);
               })
               .addSelection(tslices)
               .activate();

            var oslices = d3.selectAll(".outerSlice");
            var tooltip =
                arc.tooltip()
               .dom_id('#tooltip')
               .text_fn(function(d) {
                    return lib.tooltip_from_kvs([
                       {
                           key: columns[0].colname(),
                           value: d.data.label,
                       },
                       {
                           key: columns[1].colname(),
                           value: d.data.value,
                       },
                   ]);
               })
               .addSelection(oslices)
               .activate();
               

            if(showpercent = true) {    
    		slices.selectAll(".percent").data(_data).enter().append("text").attr("class", "percent")
    			.attr("x",function(d){ return (ir+.5)*rx*Math.cos(0.5*(d.startAngle+d.endAngle));})
    			.attr("y",function(d){ return (ir+.5)*ry*Math.sin(0.5*(d.startAngle+d.endAngle));})
    			.style("font-size", legendfsize)
    			.text(getPercent).each(function(d){this._current=d;});
            }

    	};

    	this.Donut3D = Donut3D;
    }();
 
    return f;
}();
3 Likes