View file File name : widget-dailyworkingtimechart.html.twig Content :{% set type = options.type|default('bar') %} {% set chart_id = options.id %} {% set backgroundColor = config('theme.chart.background_color') %} {% set gridColor = config('theme.chart.grid_color') %} {% set activities = data.activities %} {% set data = data.data %} <div class="chart"> <canvas id="{{ chart_id }}" style="height: {{ config('theme.chart.height') }}px;"></canvas> </div> <script type="text/javascript"> var myChart = null; var paintChart = function() { myChart = new Chart( document.getElementById('{{ chart_id }}').getContext('2d'), { type: '{{ type }}', data: { labels: [ {% for day in data -%} moment('{{ day.day|date_format('Y-m-d') }}').format('ll') {% if not loop.last %},{% endif -%} {%- endfor %} ], datasets: [ {% for activityId, activity in activities -%} {% set activityColor = activity.activity|color|default(activity.project|color|default(backgroundColor)) %} {% set activityName = activity.activity.name %} { label: '{{ activityName }}', backgroundColor: '{{ activityColor }}', borderColor: '#fff', borderWidth: 1, data: [ {%- for day in data -%} {% set realDayData = null %} {%- for entry in day.details -%} {% set loopId = (entry.project.id ~ '_' ~ entry.activity.id) %} {%- if loopId == activityId -%} {% set realDayData = entry.duration|chart_duration %} {%- endif -%} {%- endfor -%} {%- if realDayData is not null -%} '{{ realDayData }}' {%- else -%} 0 {%- endif -%} {%- if not loop.last %},{% endif -%} {%- endfor -%} ], realData: [ {%- for day in data -%} {% set realDayData = null %} {%- for entry in day.details -%} {% set loopId = (entry.project.id ~ '_' ~ entry.activity.id) %} {%- if loopId == activityId -%} {% set realDayData = {duration: entry.duration|duration, billable: day.totalDurationBillable|duration, project: entry.project.name, customer: entry.project.customer.name, activity: entry.activity.name, total: day.totalDuration|duration} %} {%- endif -%} {%- endfor -%} {%- if realDayData is not null -%} {{ realDayData|json_encode|raw }} {%- else -%} 0 {%- endif -%} {%- if not loop.last %},{% endif -%} {%- endfor -%} ] }, {%- endfor %} ] }, options: { maintainAspectRatio: true, responsive: true, legend: false, barPercentage: 0.5, categoryPercentage: 0.9, scales: { xAxes: [{ stacked: true, gridLines: { display: false }, }], yAxes: [{ stacked: true, ticks: { beginAtZero: true }, gridLines: { display: true, color: '{{ gridColor }}', lineWidth: 1 } }], }, tooltips: { callbacks: { label: function(tooltipItem, data) { var tooltipData = data.datasets[tooltipItem.datasetIndex].realData[tooltipItem.index]; return ' ' + tooltipData.duration + ': ' + tooltipData.activity; }, beforeTitle: function(tooltipItems, data) { var tooltipItem = tooltipItems[0]; var tooltipData = data.datasets[tooltipItem.datasetIndex].realData[tooltipItem.index]; return tooltipData.customer; }, title: function(tooltipItems, data) { var tooltipItem = tooltipItems[0]; var tooltipData = data.datasets[tooltipItem.datasetIndex].realData[tooltipItem.index]; return tooltipData.project; }, afterTitle: function(tooltipItems, data) { return ' '; }, footer: function(tooltipItems, data) { var tooltipItem = tooltipItems[0]; var tooltipData = data.datasets[tooltipItem.datasetIndex].realData[tooltipItem.index]; return '{{ 'stats.durationTotal'|trans }}: ' + tooltipData.total + '\n{{ 'label.billable'|trans }}: ' + tooltipData.billable; }, beforeFooter: function(tooltipItems, data) { return ' '; }, }, } } } ); }; var destroyChart = function () { myChart.destroy(); }; {% if app.request.xmlHttpRequest %} paintChart(); {% else %} document.addEventListener('kimai.initialized', paintChart); {% endif %} </script>