Files
project-work/worker-toolkit-flaredown/repo/frontend/app/components/pattern/chart-group.js

226 lines
6.1 KiB
JavaScript

import Ember from 'ember';
import moment from 'moment';
import * as d3 from "d3";
const {
get,
set,
computed,
observer,
Component,
setProperties,
A,
} = Ember;
export default Component.extend({
classNames: ['flaredown-svg-group'],
svg: null,
data: null,
svgChartWidth: 500,
svgLineAreaHeight: 150,
svgLineOffset: 20,
svgLineHeight: 3,
startAt: null,
endAt: null,
margin: { top: 20, right: 0, bottom: 5, left: 0 }, //margin for charts
backgroundMargin: { right: 10, left: 10 , top: 0 }, // for init-svg
colorIds: A(),
hasLines: false,
svgInitial: false,
init(){
this._super(...arguments);
const xScale = d3.time.scale().range([0, get(this, 'svgWidth')]);
const yScaleStatic = d3.scale.linear().range([get(this, 'svgLineAreaHeight'), 0]);
setProperties(this, { xScale, yScaleStatic });
},
didInsertElement() {
this._super(...arguments);
const svgCanvas = d3.select(this.element).select('svg');
const svgBackgroundArea = svgCanvas.append('g').attr('class', 'background-area');
const svg = svgCanvas.append('g').attr('class', 'offset');
const margin = get(this, 'margin');
svg.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // svg references to g
const resize = () => {
let svgSelection = this.$();
if(svgSelection) {
const width = this.$().width();
const backgroundMargin = get(this, 'backgroundMargin');
set(this, 'svgWidth', width);
set(this, 'svgChartWidth', width - backgroundMargin.left - backgroundMargin.right);
}
};
setProperties(this, { svgBackgroundArea, svg });
window.addEventListener("resize", resize);
resize();
},
xScaleObserver: observer('svgWidth', 'svgChartWidth', function(){
const svgInitial = get(this, 'svgInitial');
const svgWidth = get(this, 'svgWidth');
const width = svgInitial ? svgWidth - 2*get(this, 'backgroundMargin.left') : svgWidth;
get(this, 'xScale').range([0, width]);
this.renderBackground();
if(get(this, 'hasLines')) {
this.renderYGrid();
}
}),
svgBackgroundObserver: observer('svgBackgroundArea', function() {
const svgBackgroundArea = get(this, 'svgBackgroundArea');
if(!svgBackgroundArea) {
return;
}
if(svgBackgroundArea.select('rect').empty()) {
svgBackgroundArea.append('rect').attr('class', 'svg-background');
}
}),
svgGroupObserver: observer('svg', function() {
const svg = get(this, 'svg');
if(!svg) {
return;
}
if(svg.select('.grid-area').empty()) {
svg.append('g').attr('class', 'grid-area');
}
if(svg.select('.lines-area').empty()) {
const xOffset = get(this, 'svgInitial') ? get(this, 'backgroundMargin.left') : 0;
svg.append('g').attr('class', 'lines-area')
.attr('transform', `translate(${xOffset},0)`);
}
if(svg.select('.lines-dots-area').empty()) {
const xOffset = get(this, 'svgInitial') ? get(this, 'backgroundMargin.left') : 0;
svg.append('g').attr('class', 'lines-dots-area')
.attr('transform', `translate(${xOffset},0)`);
}
if(svg.select('.dots-area').empty()) {
const xOffset = get(this, 'svgInitial') ? get(this, 'backgroundMargin.left') : 0;
svg.append('g').attr('class', 'dots-area')
.attr('transform', `translate(${xOffset},0)`);
}
}),
startAtOffset: computed('startAt', 'daysRangeOffset', function() {
return moment(get(this, 'startAt')).subtract(get(this, 'daysRangeOffset'), 'days');
}),
svgHeight: computed('data.series.[]', function() {
let height = 0;
let filteredSeries = A();
const series = get(this, 'data.series') || [];
const dynamicSeries = series.filterBy('subtype', 'dynamic');
const lines = series.filterBy('type', 'line')
const markers = series.filterBy('type', 'marker');
const margin = get(this, 'margin');
filteredSeries.pushObjects([lines, dynamicSeries, markers]).map((itemArray) => {
return this.addChartAttributes(itemArray);
});
if(lines.length > 0 || dynamicSeries.length > 0) {
height += get(this, 'svgLineAreaHeight') + get(this, 'svgLineOffset');
set(this, 'hasLines', true);
} else {
height += get(this, 'svgLineOffset');
set(this, 'svgLineAreaHeight', 0);
}
if(markers.length > 0) {
markers.forEach(() => {
height += get(this, 'svgLineHeight') + get(this, 'svgLineOffset');
});
}
get(this, 'xScale').domain([
get(this, 'startAtOffset').startOf('day').toDate().getTime(),
get(this, 'endAt').endOf('day').toDate().getTime(),
]);
get(this, 'yScaleStatic').domain([0, 4]);
height += margin.top + margin.bottom;
return height || 0;
}),
svgChartHeigth: computed('svgHeight', function() {
const margin = get(this, 'margin');
return (get(this, 'svgHeight') - margin.top - margin.bottom);
}),
addChartAttributes(item_array) {
let index = get(item_array, 'firstObject.subtype') === 'dynamic' ? 10 : 0;
item_array.map((i) => {
i.index = index;
index += 1;
})
},
renderBackground() {
const backgroundMargin = get(this, 'backgroundMargin');
const svgBackgroundArea = get(this, 'svgBackgroundArea');
svgBackgroundArea.attr("transform", "translate(" + backgroundMargin.left + "," + backgroundMargin.top + ")");
svgBackgroundArea
.select('rect')
.attr('class', 'svg-background')
.attr('width', get(this, 'svgChartWidth'))
.attr('height', get(this, 'svgHeight'));
},
renderYGrid() {
const svg = get(this, 'svg');
const yScaleGrid = get(this, 'yScaleStatic');
const gridArea = svg.select('g.grid-area');
const backgroundMargin = get(this, 'backgroundMargin')
let attr = {
'class': 'yGrid',
'x1' : backgroundMargin.left,
'x2' : (get(this, 'svgWidth') - backgroundMargin.right),
'y1' : (d) => { return yScaleGrid(d) },
'y2' : (d) => { return yScaleGrid(d) },
};
let grid = gridArea.selectAll('.yGrid')
.data(yScaleGrid.ticks(5))
.attr(attr);
grid.exit().remove();
return grid.enter()
.append('line')
.attr(attr);
},
});