├── .gitattributes ├── .gitignore ├── README.md └── senseD3utils.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QlikSenseD3Utils 2 | ================ 3 | This is a library intended to help Qlik Sense Extension developers in the creation of D3 visualizations. Right now, there are only a few functions, mostly related to the creation of visualizations based on Tree Data. That being said... 4 | 5 | **PLEASE CONTRIBUTE** 6 | 7 | The idea here is that as we work on D3 visualizations in Sense we could add them to this library. D3 has several different ways of dealing with data, but as you cover one of these ways, it opens up the possibilities for many visualizations built on this data schema. 8 | For example, the createFamily function in this library takes Qlik Sense data and formats it in a way similar to the flare.json data set that you see used in many D3 visualizations. If a developer is wanting to build a viz which uses flare, it should be fairly easy to get up and running by using this createFamily function. 9 | 10 | ********************************* 11 | # Installation & Use 12 | ********************************* 13 | To get access to the function in this library, simply include the senseD3utils library in your require script in your new extension. Please see the [Zoomable Sunburst extension](https://github.com/brianwmunz/QlikSenseD3ZoomableSunbust) if you're unsure. 14 | For example: 15 | ``` 16 | define(["jquery", "text!./style.css", "./d3.v3.min", "./senseD3utils"], function($, cssContent) { 17 | 18 | ``` 19 | Once it's included, you can call the D3 functions by first using the library namespace, **senseD3**, and calling the function. So for example, to use the computeTextRotation function, you call it this way: 20 | ``` 21 | senseD3.computeTextRotation(e, x); 22 | ``` 23 | and createFamily would be called this way, with the qMatrix data being passed in: 24 | ``` 25 | senseD3.createFamily(qData.qMatrix); 26 | ``` 27 | 28 | 29 | ********************************* 30 | # Function Overview 31 | ********************************* 32 | ## createFamily 33 | 34 | This function accepts the qMatrix of data from Qlik Sense and returns a JSON object structured in a Tree parent/child format. 35 | To learn more about the Tree Layout data format, read here: 36 | 37 | [https://github.com/mbostock/d3/wiki/Tree-Layout](https://github.com/mbostock/d3/wiki/Tree-Layout) 38 | 39 | The layout that's created by createFamily is based on the commonly used data set in D3 examples called flare.json, which you can see here: 40 | 41 | [http://bl.ocks.org/mbostock/raw/4063550/flare.json](http://bl.ocks.org/mbostock/raw/4063550/flare.json) 42 | 43 | **Parameters** 44 | 45 | dataset: qMatrix - actual data values in qMatrix format 46 | 47 | numDims: integer - number of dimensions used to create the chart (use findNumOfDims(layout) if you don't want to hard code the number of dimensions) 48 | 49 | familytype: string - nested hierarchy (nested) or over multiple dimensions (multiDim) 50 | 51 | customColor: boolean - boolean based on whether custom colors are included 52 | 53 | 54 | In order for this to work properly, the data for the extension needs to be formatted in either a child/parent/value format, or using a single parent-child relationship (more on this below). This way, the function knows all of the associations between the data and can create a tree from it. Again, please see the [Sunburst extension example](https://github.com/brianwmunz/QlikSenseD3ZoomableSunbust). 55 | 56 | In your extension script, you need to first create a JSON object to hold the data tree: 57 | ``` 58 | var myJSON = {"name":layout.title,"children":[]}; 59 | ``` 60 | If you looked at the flare.json example, you'll notice that this simply creates the very top level of the tree. In this case it sets that top level to the title of the extension object. 61 | Once this is done, you simply run the function against the qMatrix data and load it in as children to the top category: 62 | ``` 63 | myJSON.children = senseD3.createFamily(qMatrix, 2, "nested", false); 64 | ``` 65 | Now you have well formatted data that can be loaded into a d3 viz. For example, the sunburst chart was easy to get running once the data was converted since most of the code that builds the viz itself doesn't need to be modified. 66 | 67 | For the numDims parameter, pass an integer for the number of dimensions (default value is 2). You can use the findNumOfDims(layout) function to get the number of dimensions if you do not have a consistent number in your extension. 68 | 69 | familytype is a string value of either "nested" or "multiDim" - "nested" if your standard tree format where there is a hierarchical relationship between child-parent. "multiDim" is used if you have a parent with only one child. 70 | 71 | The customColor parameter, takes a boolean value. The default value is false but if true, the visualization will look at the first measure, where a property has written a color code to qAttributeExpressions.0.qExpression. 72 | 73 | 74 | ## computeTextRotation 75 | 76 | this is a function used in many d3 visualizations to compute the proper rotation of the text on the viz. The required parameters for the function should be similar to what is used in the vizualization normally. The first parameter is the d3 object itself and the second is a variable that is typically represented as "x" in most d3 viz. It's essentially a range and scale of the viz: 77 | ``` 78 | senseD3.computeTextRotation(e,x); 79 | ``` 80 | 81 | ## arcTween 82 | 83 | this is another commonly seen function for animation that computes the arcs. d is once again the parameter for the object itself. It would be easiest to learn about the other parameters by looking at the sunburst extension. 84 | ``` 85 | senseD3.arcTween(d, x, y, radius, arc) 86 | ``` 87 | 88 | ## findMaxValue 89 | 90 | // Traverse the dataset to find the maximum value of a 91 | // specified attribute from all of the nodes in the passed dataset 92 | 93 | this is a commonly used function to traverse a dataset to find the maximum value of a node attribute in the current dataset view. just pass in the name of the attribute (a measure like depth or size) you're interested in and your nodes object (e.g. from a collapsible tree layout) and it will return the maximun value within the graph that a user has revealed. this can be useful for scaling your visualization to the size of the page regardless of how many nodes are visible or collapsed. 94 | ``` 95 | senseD3.findMaxDepth(nodes) 96 | ``` 97 | 98 | 99 | ## createJSONObj 100 | This function creates your standard key-value pair for all of your dimensions/measures. All keys will use the text label of the field. 101 | 102 | **Parameters** 103 | 104 | | Parameter | Required? | Description | 105 | | ------------- | ----------- | ------------------------------- | 106 | | layout | Required | This takes the layout variable from your extension | 107 | | numOfDims | Optional | This is an integer value that specifies the number of dimensions. findNumOfDims library function is used if not specified | 108 | 109 | ``` 110 | senseD3.createJSONObj(layout, 3) 111 | ``` 112 | 113 | **Return value** 114 | 115 | An array of objects for each row in your hypercube. Each object contains the dimensions and measures of that particular row. 116 | 117 | There are two types of fields in each object of the return array. The first set of field names has key value pairs of hypercube label and associated value. Because labels are used to name the keys in the object, there will often times be spaces in the names and you will have to use d["Field Name"] to reference that dimension or measure. These fields should be used sparingly since the user can alter the label names. 118 | 119 | The second set of fields returns fields in the format dim_X_id, dim_X, meas_X, meas_X_txt, and meas_X_attr_Y to give standard formatted field names that can be used regardless of the naming of each dimension or measure. 120 | 121 | 122 | ## findNumOfDims 123 | This function is used to find how many dimensions are contained in your HyperCube. This is useful for passing the numDims parameter for other functions. 124 | 125 | **Parameters** 126 | 127 | layout: layout - this takes the layout variable from your extension 128 | 129 | 130 | ``` 131 | senseD3.findNumOfDims(layout) 132 | ``` 133 | 134 | **Return Value** 135 | 136 | Single integer specifying the length of the dimension object 137 | -------------------------------------------------------------------------------- /senseD3utils.js: -------------------------------------------------------------------------------- 1 | var senseD3 = { 2 | arcTween: function(d, x, y, radius, arc) { 3 | var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]), 4 | yd = d3.interpolate(y.domain(), [d.y, 1]), 5 | yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]); 6 | return function(d, i) { 7 | return i ? function(t) { 8 | return arc(d); 9 | } : function(t) { 10 | x.domain(xd(t)); 11 | y.domain(yd(t)).range(yr(t)); 12 | return arc(d); 13 | }; 14 | }; 15 | 16 | }, 17 | computeTextRotation: function(d, x) { 18 | return (x(d.x + d.dx / 2) - Math.PI / 2) / Math.PI * 180; 19 | }, 20 | //create family is to be used for creating a tree type data structure which can be used in most D3 tree vizualizations. 21 | //See more info about the tree layout here: https://github.com/mbostock/d3/wiki/Tree-Layout 22 | // takes parameters for: 23 | // dataset : qMatrix - actual data values 24 | // numDims : int - number of dimensions used to create the chart 25 | // familytype : string - nested (nested) or over multiple dimensions (multiDim) 26 | // customColor : boolean - boolean if custom colors are included 27 | createFamily: function(dataSet,numDims,familytype,customColor) { 28 | var numDims; 29 | if (arguments.length==1) { 30 | familytype = "multiDim", 31 | numDims = 2, 32 | customColor=false; 33 | } else if(arguments.length==2) { 34 | familytype = "multiDim", 35 | customColor=false; 36 | } else if (arguments.length==3) { 37 | customColor=false; 38 | }; 39 | 40 | //create arrays of parents and children. this is so we can determine if there's any nodes without parents. these would be the top parents 41 | var parentsA = []; 42 | var kidsA = []; 43 | 44 | //create array for data that will be added on each loop 45 | var happyData = []; 46 | 47 | //loop through each array in the dataset 48 | for(s=0; s maxValue ? d[attr] : maxValue); 221 | }); 222 | return maxValue; 223 | }, 224 | findNumOfDims: function (layout) { 225 | //return the number of dimensions 226 | return layout.qHyperCube.qDimensionInfo.length; 227 | } 228 | }; 229 | --------------------------------------------------------------------------------