import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import { StateService } from '../state.service'; import zingchart from 'zingchart/es6'; import * as d3 from 'd3'; @Component({ selector: 'app-overview-window', templateUrl: './overview-window.component.html', styleUrls: ['./overview-window.component.css'] }) export class OverviewWindowComponent implements OnInit { @ViewChild('chart') chart; private initialHeight; public config; public graphset = []; public id = 'overview'; public markers = []; public series = []; public goodLabels = []; public badLabels = []; public candidateLabels = []; public pathWidth = 100; public allChannels: number[]; public data; public layout; constructor(private state: StateService, private el: ElementRef) { } async ngOnInit(): Promise { this.initialHeight = this.el.nativeElement.offsetHeight; // this.state.onNewData.subscribe(() => this.dostuff3()); this.state.onNewData.subscribe(() => this.initializePlot()); this.state.onNewLshData.subscribe(() => this.updatePlot()); this.state.onNewSelection.subscribe(() => this.updateChannels()); } dostuff3() { let y_val = 0; let N = 200000; let values = d3.range(N).map(function(x, i, arr) { y_val += Math.random() - 0.5; return {x: x, y: y_val, id: i}; }); console.log(values); let margin = {top: 30, right: 30, bottom: 30, left: 20 }; let width = 600 - margin.left - margin.right; let height = 150 - margin.top - margin.bottom; const svg = d3.select('.test') .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let xscale = d3.scaleLinear().domain([0, N]).range([0, N]); const x2 = xscale.copy(); // reference. const yscale = d3.scaleLinear().domain([-10, 10]).range([height, 0]); const line = d3.line() .x(function(d:any) { return xscale(d.x); }) .y(function(d:any) { return yscale(d.y); }) const axis = d3.axisBottom(xscale); const axis_G = svg.append("g") .attr("transform", "translate(0," + height + ")") .call(axis); const axis_left = svg.append("g") .call(d3.axisLeft(yscale)); const lines = svg.append('g') .data([values]) .append('path') .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-width", 1.5) .attr('class', 'data') .attr('d', (d: any) => line(d)); const zoomed = function() { console.log(d3.event.transform); const transform = d3.event.transform; // lines.attr("transform", d3.event.transform); xscale = transform.rescaleX(x2); axis.scale(xscale); axis_G.call(axis); svg.select('.data').attr('d', (d: any) => { return d3.line() .x(function(d:any) { return transform.applyX(xscale(d.x)); }) .y(function(d:any) { return yscale(d.y); })(d); }); }; const zoom = d3.zoom() .scaleExtent([1, 10000]) .on('zoom', zoomed); svg.call(zoom); } async initializePlot() { this.allChannels = [...Array(this.state.rawData.length).keys()]; this.state.queryWindow = undefined; // this.debugClicked(); this.graphset.push({ id: 'preview', type: "scatter", x: 0, y: 0, scaleX: { zooming: true, minValue: 0, maxValue: this.state.rawData[0].values.length, zoomTo: [0, this.state.windowSize], 'auto-fit': true, visible: false, guide: { visible: false } }, height: '30px', scaleY: { maxValue: 1, minValue: -1, visible: false, guide: { visible: false } }, preview: { x: 50, y: 10, height: '30px', }, series: [ { type: 'scatter', values: [], text: 'Good labels', marker: { backgroundColor: '#4caf50' }, zIndex: 3, }, { type: 'scatter', values: [], text: 'Bad labels', marker: { backgroundColor: '#f44336' }, zIndex: 2, }, { type: 'scatter', values: [], text: 'Candidates', marker: { backgroundColor: '#b1a343' }, zIndex: 1, } ] }); // Initialize channels console.log(this.state); console.log(this.state.selection); this.state.selection.forEach((channelIndex, index) => { const channel = this.state.rawData[channelIndex]; const data = []; for (let i = 0; i < channel.values.length; i++) { data.push([i, channel.values[i]]); } this.graphset.push({ id: index, x: 0, y: `${75 * index + 50}px`, type: 'line', height: '50px', scaleX: { zooming: true, zoomTo: [0, this.state.windowSize], markers: [] }, 'scale-y': { zooming: false, 'auto-fit': true }, plotarea: { height: '50px', 'margin-top': '0px', 'margin-bot': '0px' }, series: [{ type: 'line', values: data, text: 'Raw Values', zIndex: 5, marker: { alpha: 0.0, zIndex: 10 } }] }); }); zingchart.bind('zingchart-ng-1', 'zoom', (e) => { if (e.graphid !== `zingchart-ng-1-graph-preview`) { return; } for (let i = 1; i < this.graphset.length; i ++) { this.chart.zoomto({ graphid: i, xmin: e.xmin, xmax: e.xmax }); } }); this.config = { layout: `${this.graphset.length}x1`, graphset: this.graphset }; this.chart.setdata({ data: this.config }); console.log(this.config); console.log("showing plot"); await this.debugClicked(); } // changeSelection() { // this.state.selection = [0, 1, 2]; // } async updateChannels() { console.log('updating plot'); this.graphset = this.graphset.slice(0, 1); this.state.selection.forEach((channelIndex, index) => { const channel = this.state.rawData[channelIndex]; const data = []; for (let i = 0; i < channel.values.length; i++) { data.push([i, channel.values[i]]); } this.graphset.push({ id: channelIndex, x: 0, y: `${75 * index + 50}px`, type: 'line', height: '50px', scaleX: { zooming: true, zoomTo: [0, this.state.windowSize], markers: [] }, 'scale-y': { zooming: false, 'auto-fit': true }, plotarea: { height: '50px', 'margin-top': '0px', 'margin-bot': '0px' }, series: [{ type: 'line', values: data, text: 'Raw Values', zIndex: 5, marker: { alpha: 0.0, zIndex: 10 } }] }); }); this.config = { layout: `${this.graphset.length}x1`, graphset: this.graphset }; this.chart.setdata({ data: this.config }); // this.chart.addgraph(this.graphset[4]); console.log(this.config); console.log("showing plot"); } async updatePlot() { console.log('updating plot'); if (!this.state.queryWindow) { return; } this.goodLabels = []; this.badLabels = []; this.markers = []; for (const index in this.state.labels) { if (this.state.labels[index]) { this.goodLabels.push([Number(index), 0]); this.markers.push({ type: 'area', // BUG: For some reason the range values are multiplied by 10 range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10], backgroundColor: "#4caf50", }); } else { this.badLabels.push([Number(index), -1]); this.markers.push({ type: 'area', // BUG: For some reason the range values are multiplied by 10 range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10], backgroundColor: "#f44336", }); } } for (const index of this.state.lshData.samples) { this.candidateLabels.push([Number(index), 0]); this.markers.push({ type: 'area', // BUG: For some reason the range values are multiplied by 10 range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10], backgroundColor: '#b1a343', }); } console.log(this.markers); for (const channel of this.config.graphset) { if (channel.type === 'line') { channel.scaleX.markers = this.markers; } else { channel.series[0].values = this.goodLabels; channel.series[1].values = this.badLabels; channel.series[2].values = this.candidateLabels; } } this.chart.setdata({ data: this.config }); } ping() { console.log("ping"); } async updateCandidates(sliderIndex) { // let candidates = []; // for (let i = sliderIndex; i < this.service.nrOfTables; i++) { // candidates = candidates.concat(this.service.windowSimilarity[sliderIndex.toString()]); // } // const labels = []; // const markers = []; // for (const index of candidates) { // labels.push([Number(index) * (12000 / 6), 0]); // markers.push({ // type: 'area', // // BUG: For some reason the range values are multiplied by 10 // range: [Number(index) * (12000 / 6) / 10, (Number(index) * (12000 / 6) + this.state.windowSize) / 10], // backgroundColor: '#b1a343', // }); // } // const newSeries = this.config.series.slice(0, 3); // newSeries.push({ // type: 'scatter', // values: labels, // text: 'Similar windows', // marker: { // backgroundColor: '#b1a343' // }, // zIndex: 20, // }); // this.config.series = newSeries; // this.config.scaleX.markers = this.markers.concat(markers); // zingchart.exec('zingchart-ng-1', 'setdata', { // data: this.config // }); } async clicked(clickData) { if (!this.state.querySelectionMode) { return; } this.state.querySelectionMode = false; await this.debugClicked(); return; const xyInformation = zingchart.exec('zingchart-ng-1', 'getxyinfo', { x: clickData.x, y: clickData.y }); const index = Math.floor(xyInformation[0].scalenumvalue / (12000 / 6)); await this.state.getQueryWindow(index); await this.state.lshInitial(); const temp = {}; temp[index] = true; this.state.labels = temp; } async debugClicked() { const index = 6713; await this.state.getQueryWindow(index); await this.state.lshInitial(); const temp = {}; temp[index] = true; this.state.labels = temp; } zoom(p) { if (!p.ev) { return; } if (p.ev.wheelDelta > 0) { zingchart.exec("zingchart-ng-1", 'zoomin'); } else if (p.ev.wheelDelta < 0) { zingchart.exec("zingchart-ng-1", 'zoomout'); } } isInSelection(i): boolean { return i in this.state.selection; } changeSelection(i: number): void { if (i in this.state.selection) { this.state.selection = this.state.selection.filter((v) => v !== i); } else { const selection = this.state.selection; selection.push(i); this.state.selection = selection; } } get height(): number { return Math.max(75 * this.state.selection.length + 50, this.initialHeight); } }