Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Page properties
hiddentrue


UI Text Box
sizemedium
typeinfo

This chart is an example with 2 Y axes, that can be used for correlating values (Money vs. Time Spent, Original Estimate vs. Time Spent), grouped by a certain category.

Button Hyperlink
iconapprove
titleDownload Scripted Chart Bundle
typeprimary
urlhttps://apps.decadis.net/download/attachments/1807530/2Y%20Axes%20Chart.json?api=v2

Chart preview

Parameters

NameTypeDefault
UICode

JQL

JQLJQL Autocomplete
Group By XGroupByX

Group By Picker

Issue Type
Values On YValuesOnYValue Field PickerIssueCount
Values On Y2ValuesOnY2Value Field PickerAttachmentCount
UI Expand
titleLayout Script
Code Block
languagejs
themeMidnight
linenumberstrue
function formatTooltipAsHours(value, ratio, id, index)
{
    return value.toFixed(2) + ' h';
}
 
var c3arg = {
    data: chartData,
    grid: {
      y: {
        show: true
      },
      x: {
        show: true
      }
    },
    axis: {
        x: {
            type: 'category',
            label: {
                text: chartData.xtype,
                position: 'outer-right'
            }
        },
        y: {
            label: chartData.custom.yType
        },
        y2: {
            label: chartData.custom.y2Type,
            show: true
        }
    },
    zoom: {
        enabled: true
    }
};
 
 
if (chartData.custom && chartData.custom.tooltip)
{
    var tooltipFunction = eval(chartData.custom.tooltip);
    c3arg.tooltip = {
        format: {
            value: tooltipFunction
        }
    };
}
 
c3.generate(c3arg);
UI Expand
titleData Script
Code Block
languagejs
themeMidnight
linenumberstrue
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Calendar;
import java.math.RoundingMode;
 
import org.apache.lucene.document.Document;
 
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.DocumentIssueImpl;
import com.atlassian.jira.jql.parser.JqlParseException;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.query.Query;
 
import com.decadis.jira.xchart.api.model.Period;
import com.decadis.jira.xchart.api.util.DateUtils;
import com.decadis.jira.xchart.api.model.ChartData;
 
import com.decadis.jira.xchart.utils.JiraFieldUtil;
 
BigDecimal transformSecondsToHours(BigDecimal secondsAsBD)
{
  return secondsAsBD.divide(BigDecimal.valueOf(3600.0), 2, RoundingMode.HALF_UP);
}
 
def addValueAsHours(metaCountGroup, valueExtractor, issue, document, group)
{
  metaCountGroup.addValue(transformSecondsToHours(valueExtractor.get(issue, document)), valueExtractor.getTitle(), group);
}
 
def metaCountGroup = chartBuilder.newDataCollector();
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
 
JqlQueryParser jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class);
Query query = null;
try {
  query = jqlQueryParser.parseQuery(JQL); //JQL is a parameter of type Jql Autocomplete Picker
} catch (JqlParseException e) {
  throw new IllegalArgumentException("Bad JQL: " + query);
}
  
def valueExtractorY = chartBuilder.getValueExtractor(ValuesOnY);
if ( valueExtractorY == null ) {
  throw new IllegalArgumentException("No value extractor implemtation for " + ValuesOnY);
}
 
def valueExtractorY2 = chartBuilder.getValueExtractor(ValuesOnY2);
if ( valueExtractorY2 == null ) {
  throw new IllegalArgumentException("No value extractor implemtation for " + ValuesOnY2);
}
 
def groupValueExtractor = chartBuilder.getGrouper(GroupByX);
 
Field documentField;
try
{
  documentField = DocumentIssueImpl.class.getDeclaredField("document");
  documentField.setAccessible(true);
  for ( Issue issue : chartBuilder.getFilterUtils().performSearch(query, user) )
  {
    Document document = (Document) documentField.get(issue);
    for ( String groupX : groupValueExtractor.getGroups((Document) documentField.get(issue)) )
    {
      group = groupValueExtractor.getResolvedValue(groupX, issue);
      if ( JiraFieldUtil.isTimeTrackingField(ValuesOnY)) {
        addValueAsHours(metaCountGroup, valueExtractorY, issue, document, group);
      }
      else {
        metaCountGroup.addValue(valueExtractorY.get(issue, document), valueExtractorY.getTitle(), group);
      }
 
      if (JiraFieldUtil.isTimeTrackingField(ValuesOnY2)) {
        addValueAsHours(metaCountGroup, valueExtractorY2, issue, document, group);
      }
      else {
        metaCountGroup.addValue(valueExtractorY2.get(issue, document), valueExtractorY2.getTitle(), group);
      }
    }
  }
} catch (Exception e){
    System.err.println("Exception " + e);
}
  
def chartData = chartBuilder.newChartData("Issues");
 
for ( String grpKey : metaCountGroup.keySet() )
{
  chartData.addGroupName(grpKey, groupValueExtractor.getResolvedValue(grpKey, null));
}
 
chartData.setChartType(valueExtractorY.getTitle(), "bar");
chartData.setChartType(valueExtractorY2.getTitle(), "line");
 
chartData.setXType(groupValueExtractor.getGroupName());
 
chartData.setYAxis(valueExtractorY.getTitle(), "y");
chartData.setYAxis(valueExtractorY2.getTitle(), "y2");
 
chartData.addCustomData("y2Type", valueExtractorY2.getTitle());
chartData.addCustomData("yType", valueExtractorY.getTitle());
 
if ( JiraFieldUtil.isTimeTrackingField(ValuesOnY) || JiraFieldUtil.isTimeTrackingField(ValuesOnY2) )
{
  chartData.addCustomData("tooltip", "formatTooltipAsHours");
}
  
chartBuilder.getChartUtil().transformResult(metaCountGroup, chartData, false);
  
return chartData;

Related examples

Page properties report
cqllabel = "chart_script_example" and space = currentSpace()


Excerpt Include
DECADIS:Contact support
DECADIS:Contact support
nopaneltrue