Hi,
I'm using the igDataChart and I want to show the legends of a particular series. The only way I found to do this is to create a custom <div> in wich legend are going to be shown, assign an id and then set the id in the element option of the legend.
<div>
element
legend
To start with, I'm not even sure why I need to create the div element as it perfectly could be created by the igDataChart control itself. Besides, I don't want to have an id in that div as I will be showing multiple charts on the same page and having ids could lead to an id duplication. How can I do to set the element option in some other way (i.e. custom selector, jQuery object or DOM Element)?
Thanks,
Hello Hugo,
Thank you for contacting Infragistics Support!
After doing some research, I found that when the legend property of the igDataChart is set (legend: { element: “elementID” }) it internally tries to find a DOM element with id = “elemendID”. As soon as such element has been found an html table would be rendered within it. Each row of this table will represent a particular series of the chart.
Having this in mind you can consider this element (which could be actually not only <div> but any other selector as well (span, p etc.)) as a hook which will indicate the igDataChart where to render its legend.
Having this in mind I can verify that currently the only way of using the build-in legend functionality is via providing the id of some DOM element to the igDataChart. In case your requirements is to pass not an id but an HTML element or something else I can suggest submitting a new product idea. You can suggest new product ideas for future versions (or vote for existing ones) here.
There are many benefits to submitting a product idea:
- Direct communication with our product management team regarding your product idea.
- Notifications whenever new information regarding your idea becomes available.
- Ability to vote on your favorite product ideas to let us know which ones are the most important to you. You will have ten votes for this and can change which ideas you are voting for at any time.
- Allow you to shape the future of our products by requesting new controls and products altogether.
- You and other developers can discuss existing product ideas with members of our Product Management team.
Steps to create your idea:
The Product Idea site puts you in the driver’s seat and allows you to track the progress of your ideas at any time, see how many votes it got, read comments from other developers in the community, and see if someone from the product team has additional questions for you.
Please let me know if you need any further information!
Best Regards, Martin Evtimov Associate Software Developer Infragistics, Inc.
Hi Martin, thanks for the reply.
I've just suggested the product idea although at this point of maturity of the product I think this kind of things are closer to an issue rather than just a suggestion.
Anyways, I'd also very much appreciate your help with another thing related to chart's legend. I have a stacked-bar chart like so:
The legend I want to show is regarding each fragment on the bars (i.e., each color). But I want to show not only the fragment name but also a value for that fragment in the whole graph. I cannot seem to find how can I customize the legend's content. How can I do this?
Thanks
Hello Hugo,I created an example how you can choose which stacked fragments to show (using fragment's legendItemVisibility property) in the legend as well as display sum of values in a given stacked fragment (using fragment's title property).Let me know if you have more questions.
<!DOCTYPE html> <html> <head> <title>DC Stacked Series + Legend</title> <!-- Ignite UI Required Combined CSS Files --> <link href="http://cdn-na.infragistics.com/igniteui/2019.2/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2019.2/latest/css/structure/infragistics.css" rel="stylesheet" /> <!--CSS file specific for chart styling --> <link href="http://cdn-na.infragistics.com/igniteui/2019.2/latest/css/structure/modules/infragistics.ui.chart.css" rel="stylesheet" /> <script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script> <!-- Ignite UI Required Combined JavaScript Files --> <script src="http://cdn-na.infragistics.com/igniteui/2019.2/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2019.2/latest/js/infragistics.dv.js"></script> </head> <body> <script type="text/javascript" src="https://www.igniteui.com/data-files/world-energy-production.js"></script> <script> $(function () { var dataItems = getDataSource(); $("#chart").igDataChart({ height: "300px", width: "100%", horizontalZoomable: true, verticalZoomable: true, windowResponse: "immediate", title: "Stacked Bar Chart", legend: { element: "legend" }, dataSource: dataItems, axes: [{ name: "yAxis", type: "categoryY", label: "Year", }, { name: "xAxis", type: "numericX", }], series: [ CreateStackedSeries(), ], }); function CreateStackedSeries() { var series = { name: "stackedBarSeries", type: "stackedBar", xAxis: "xAxis", yAxis: "yAxis", outline: "transparent", series: [ // create stacked fragment and show it legend item based on passed boolean CreateStackedWithLegend(true, "Canada"), CreateStackedWithLegend(true, "Russia"), CreateStackedWithLegend(false, "China"), CreateStackedWithLegend(true, "UnitedStates"), CreateStackedWithLegend(false, "SaudiArabia"), ] } return series; } function CreateStackedWithLegend(showLegendItem, memberPath) { var stackFragment = { name: memberPath + "Fragment", valueMemberPath: memberPath, type: "stackedFragment", showTooltip: true, tooltipTemplate: memberPath, }; if (!showLegendItem) { stackFragment.legendItemVisibility = "collapsed"; stackFragment.title = memberPath; } else { stackFragment.legendItemVisibility = "visible"; // calculating total for the stacked fragment and setting to it to title that will show in legend let total = 0; for (const item of dataItems) { total += item[memberPath]; } stackFragment.title = memberPath + ": " + Math.round(total) + "M (total)"; } return stackFragment; } function getDataSource(){ var data = [ { "Year": 2005, "Canada": 18.8932, "SaudiArabia": 25.4401, "Russia": 51.0796, "UnitedStates": 69.4437, "China": 63.9524, }, { "Year": 2006, "Canada": 19.2273, "SaudiArabia": 24.6105, "Russia": 52.0557, "UnitedStates": 70.7539, "China": 68.2333, }, { "Year": 2007, "Canada": 19.5439, "SaudiArabia": 23.7326, "Russia": 52.5599, "UnitedStates": 71.4000, "China": 73.2809, }, { "Year": 2008, "Canada": 19.0196, "SaudiArabia": 25.1682, "Russia": 52.5460, "UnitedStates": 73.2178, "China": 78.3599, }, { "Year": 2009, "Canada": 18.3249, "SaudiArabia": 22.837, "Russia": 50.4291, "UnitedStates": 72.6409, "China": 84.0643, }, { "Year": 2010, "Canada": 18.3358, "SaudiArabia": 24.7442, "Russia": 53.2232, "UnitedStates": 74.7951, "China": 90.3918, } ]; return data; } }); </script> <div style="width: 100%; height: 100%; display: flex; flex-direction: column;"> <div id="chart"></div> <div id="legend" ></div> </div> </body> </html>
Hi Martin. That worked awesome, thanks for your fast reply!
There is one last thing you can help me with. I'd also like to show the value of each fragment somehow. For example, Canada in 2005: 18.8923. As far as I understand, showing text on the bar itself is currently not supported. I thought I could use the tooltips instead. How can I customize them so that they show both the fragment name and the value in the bar where the mouse is.
For example, if I were to put the cursor over the purple on 2005 it should show "Canada 18.8923" but in 2006 "Canada 19.2273".
Thank you very much
I implemented custom tooltip that displays fragment name and its value when the end-user hovers over fragments.
<!DOCTYPE html> <html> <head> <title>DC Stacked Series + Legend</title> <!-- Ignite UI Required Combined CSS Files --> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/structure/infragistics.css" rel="stylesheet" /> <!--CSS file specific for chart styling --> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/structure/modules/infragistics.ui.chart.css" rel="stylesheet" /> <script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script> <!-- Ignite UI Required Combined JavaScript Files --> <script src="http://cdn-na.infragistics.com/igniteui/2020.2/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2020.2/latest/js/infragistics.dv.js"></script> </head> <body> <div style="width: 100%; height: 100%; display: flex; flex-direction: column;"> <div id="chart"></div> <div id="legend"></div> </div> <!-- Custom Tooltip Template --> <script id="tooltipTemplate" type="text/x-jquery-tmpl"> <div> {{if ${series.valueMemberPath} === "Canada"}} Country: <span style="font-weight: bold">Canada</span><br/> Value: <span style="font-weight: bold">${item.Canada} M</span><br/> {{elseif ${series.valueMemberPath} === "China"}} Country: <span style="font-weight: bold">China</span><br/> Value: <span style="font-weight: bold">${item.China} M</span><br/> {{elseif ${series.valueMemberPath} === "UnitedStates"}} Country: <span style="font-weight: bold">United States</span><br/> Value: <span style="font-weight: bold">${item.UnitedStates} M</span><br/> {{elseif ${series.valueMemberPath} === "Russia"}} Country: <span style="font-weight: bold">Russia</span><br/> Value: <span style="font-weight: bold">${item.Russia} M</span><br/> {{elseif ${series.valueMemberPath} === "SaudiArabia"}} Country: <span style="font-weight: bold">Saudi Arabia</span><br/> Value: <span style="font-weight: bold">${item.SaudiArabia} M</span><br/> {{/if}} Year: <span style="font-weight: bold">${item.Year}</span><br/> </div> </script> <script type="text/javascript"> $(function () { var dataItems = getDataSource(); $("#chart").igDataChart({ height: "300px", width: "100%", horizontalZoomable: true, verticalZoomable: true, windowResponse: "immediate", title: "Stacked Bar Chart", legend: { element: "legend" }, dataSource: dataItems, axes: [{ name: "yAxis", type: "categoryY", label: "Year", }, { name: "xAxis", type: "numericX", }], series: [ CreateStackedSeries(), ], }); function CreateStackedSeries() { var series = { name: "stackedBarSeries", type: "stackedBar", xAxis: "xAxis", yAxis: "yAxis", outline: "transparent", series: [ // create stacked fragment and show it legend item based on passed boolean CreateStackedWithLegend(true, "Canada"), CreateStackedWithLegend(true, "Russia"), CreateStackedWithLegend(true, "China"), CreateStackedWithLegend(true, "UnitedStates"), CreateStackedWithLegend(true, "SaudiArabia"), ] } return series; } function CreateStackedWithLegend(showLegendItem, memberPath) { var stackFragment = { name: memberPath + "Fragment", valueMemberPath: memberPath, type: "stackedFragment", showTooltip: true, // setting custom tooltip tooltipTemplate: "tooltipTemplate" }; var country = memberPath; if (country === "UnitedStates") country = "United States"; if (country === "SaudiArabia") country = "Saudi Arabia"; if (!showLegendItem) { stackFragment.legendItemVisibility = "collapsed"; stackFragment.title = country; } else { stackFragment.legendItemVisibility = "visible"; // calculating total for the stacked fragment and setting to it to title that will show in legend let total = 0; for (const item of dataItems) { total += item[memberPath]; } stackFragment.title = country + ": " + Math.round(total) + "M (total)"; } return stackFragment; } function getDataSource(){ var data = [ { "Year": 2005, "Canada": 18.8932, "SaudiArabia": 25.4401, "Russia": 51.0796, "UnitedStates": 69.4437, "China": 63.9524, }, { "Year": 2006, "Canada": 19.2273, "SaudiArabia": 24.6105, "Russia": 52.0557, "UnitedStates": 70.7539, "China": 68.2333, }, { "Year": 2007, "Canada": 19.5439, "SaudiArabia": 23.7326, "Russia": 52.5599, "UnitedStates": 71.4000, "China": 73.2809, }, { "Year": 2008, "Canada": 19.0196, "SaudiArabia": 25.1682, "Russia": 52.5460, "UnitedStates": 73.2178, "China": 78.3599, }, { "Year": 2009, "Canada": 18.3249, "SaudiArabia": 22.837, "Russia": 50.4291, "UnitedStates": 72.6409, "China": 84.0643, }, { "Year": 2010, "Canada": 18.3358, "SaudiArabia": 24.7442, "Russia": 53.2232, "UnitedStates": 74.7951, "China": 90.3918, } ]; return data; } }); </script> </body> </html>
Hi Martin.
Thanks for your example. That works and its close from what I need. I still have one issue though. I do not have fixed categories for each fragment that I can write in the template (like Canada, China, etc.).
So I've tried different approaches to get the template as I need it but none of them worked. I'll share the details one by one.
Simple approach:
Template:
<span>${series.valueMemberPath}</span> <span>${item[${series.valueMemberPath}]}</span>
Result:
Function approach
<span>${globalGetValue(item, series.valueMemberPath)}</span>
Function defined in JS file in a global scope:
function globalGetValue(item, prop) { console.log("function called!"); return item[prop]; }
Tooltip is shown but uses the variables/functions defined in the template litarally:
Iteration approach:
{{each(prop, val) item}} {{if ${series.valueMemberPath} === ${prop}}} <span>${prop}</span> <span>${val}</span> {{/if}} {{/each}}
No tooltip is shown at all.
to provide better solution, I will need your data source and source code that you use to create the chart. So can you post it here?
Thanks for the reply, it worked!
That'd be all, at least with this post. I've posted another question related to igDataChart 22 days ago and there's been no answer. Here it is the link: (+) igDataChart stackedBar animation | Infragistics Forums.
Thanks!
I modified tooltip template in my sample and I added tooltipShowing function on the DataChart to store value of an item for a given series.valueMemberPath as item.tooltipValue property:
<!DOCTYPE html> <html> <head> <title>DC Stacked Series + Tooltip</title> <!-- Ignite UI Required Combined CSS Files --> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/structure/infragistics.css" rel="stylesheet" /> <!--CSS file specific for chart styling --> <link href="http://cdn-na.infragistics.com/igniteui/2020.2/latest/css/structure/modules/infragistics.ui.chart.css" rel="stylesheet" /> <script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script> <!-- <script type='text/javascript' src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script> --> <!-- Ignite UI Required Combined JavaScript Files --> <script src="http://cdn-na.infragistics.com/igniteui/2020.2/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2020.2/latest/js/infragistics.dv.js"></script> </head> <body> <div style="width: 100%; height: 100%; display: flex; flex-direction: column;"> <div id="chart"></div> <div id="legend"></div> </div> <!-- Custom Tooltip Template --> <script id="tooltipTemplate" type="text/x-jquery-tmpl"> <div> <div>Data Name: ${item.Year}</div> <div>Column Name: ${series.valueMemberPath} </div> <!-- note that tooltipValue is added in the tooltipShowing function --> <div>Column Value: ${item.tooltipValue} </div> <!-- note this syntax is not supported: --> <!-- <div>Column Value: ${item.${series.valueMemberPath}} </div> --> </div> </script> <script type="text/javascript"> $(function () { var dataItems = getDataSource(); var dataColumns = []; var dataTotals = {}; for (i = 0; i < dataItems.length; i++) { for (var key in dataItems[i]) { if (key == "Year") continue; if (i == 0) { dataColumns.push(key); dataTotals[key] = 0; } dataTotals[key] += dataItems[i][key]; } } $("#chart").igDataChart({ height: "300px", width: "100%", horizontalZoomable: true, verticalZoomable: true, windowResponse: "immediate", title: "Stacked Bar Chart", legend: { element: "legend" }, dataSource: dataItems, // added this function to resolve displaying values in tooltip templates tooltipShowing: function (e, ui) { var valueMemberPath = ui.series.valueMemberPath; ui.item.tooltipValue = ui.item[valueMemberPath]; }, axes: [{ name: "yAxis", type: "categoryY", label: "Year", }, { name: "xAxis", type: "numericX", }], series: [ CreateStackedSeries() ], }); function CreateStackedSeries() { var series = { name: "stackedBarSeries", type: "stackedBar", xAxis: "xAxis", yAxis: "yAxis", showDefaultTooltip: true, series: CreateFragments(dataColumns) } return series; } function CreateFragments(dataColumns) { var fragments = []; for (i = 0; i < dataColumns.length; i++) { var key = dataColumns[i]; console.log("CreateFragments " + key); var fragment = CreateStackedFragment(key); fragments.push(fragment); } return fragments; } function CreateStackedFragment(memberPath) { var stackFragment = { name: memberPath + "Fragment", valueMemberPath: memberPath, type: "stackedFragment", showTooltip: true, title: memberPath + " (" + Math.round(dataTotals[memberPath]) + " Total)", tooltipTemplate: "tooltipTemplate" }; return stackFragment; } function getDataSource(){ var data = [ { "Year": 2005, "Canada": 18.8932, "Europe": 25.4401, "Russia": 51.0796, "America": 69.4437, "China": 63.9524, }, { "Year": 2006, "Canada": 19.2273, "Europe": 24.6105, "Russia": 52.0557, "America": 70.7539, "China": 68.2333, }, { "Year": 2007, "Canada": 19.5439, "Europe": 23.7326, "Russia": 52.5599, "America": 71.4000, "China": 73.2809, }, ]; return data; } }); </script> </body> </html>
Martin,
I'm pretty sure there is no need for this as the issue with the tooltip seems pretty clear by itself. However I have created this simplified version of my code.
<div class="chart" id="chart"></div> <div class="chart-legend chart-legend-horizontal" id="chartLegend"></div> <script type="text/x-jquery-tmpl" id="template"> <div>${series.valueMemberPath}: ${item.${series.valueMemberPath}}</div> </script> <script type="text/javascript"> function linqSelect(arr, fnSelect) { var newArr = []; for (var i = 0; i < arr.length; i++) { newArr.push(fnSelect(arr[i])); } return newArr; }; let dataSource = [{"DiaSemana":"Martes","ENF4":0,"ENFE":5,"ADAVI":1,"CAP":4},{"DiaSemana":"Lunes","ENF4":0,"ENFE":7,"ADAVI":1,"CAP":8},{"DiaSemana":"Domingo","ENF4":0,"ENFE":7,"ADAVI":1,"CAP":8},{"DiaSemana":"Sábado","ENF4":0,"ENFE":5,"ADAVI":1,"CAP":7},{"DiaSemana":"Viernes","ENF4":0,"ENFE":2,"ADAVI":1,"CAP":1},{"DiaSemana":"Jueves","ENF4":0,"ENFE":7,"ADAVI":1,"CAP":6},{"DiaSemana":"Miércoles","ENF4":0,"ENFE":3,"ADAVI":1,"CAP":4}]; let xAxis = { name: "xAxis", type: "numericX" }, yAxis = { name: "yAxis", type: "categoryY", label: "DiaSemana", gap: 0.5, }, ausencias = [], totales = {}; for (i = 0; i < dataSource.length; i++) { for (var key in dataSource[i]) { if (key == "DiaSemana") continue; if (i == 0) { ausencias.push(key); totales[key] = 0; } totales[key] += dataSource[i][key]; } } $("#chart").igDataChart({ dataSource: dataSource, height: 300, width: "100%", title: "Chart Title", axes: [xAxis, yAxis], legend: { element: "chartLegend" }, series: [ { name: "series", type: "stackedBar", xAxis: xAxis.name, yAxis: yAxis.name, outline: "transparent", isTransitionInEnabled: true, series: linqSelect(ausencias, function (a) { return { name: a + "Fragment", valueMemberPath: a, type: "stackedFragment", showTooltip: true, tooltipTemplate: "template", legendItemVisibility: "visible", title: a + " " + totales[a] }; }) } ] }); </script>
Yes, please provides us with a simplified example to isolate this issue and we will try to create a solution for it.
Unfortunately, that didn't work as expected. Here it is its result:
It wouldn't be easy for me to share the data and source code because it's being generated in a way more complex scenario. If you really need it I can try and create a simplified example although I believe the issue is isolated enough.
Please let me know how we should continue.