<!DOCTYPE html>
<html>

  <head>
    <base href="." />
    <title>angular2 playground</title>
    <link rel="stylesheet" href="style.css" />
    <script src="https://unpkg.com/zone.js/dist/zone.js"></script>
    <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
    <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
    <script src="config.js"></script>
    <script>
    System.import('app')
      .catch(console.error.bind(console));
  </script>
  </head>

  <body>
    <my-app>
    loading...
  </my-app>
  </body>

</html>
/* Master Styles */
h1 {
  color: #369; 
  font-family: Arial, Helvetica, sans-serif;   
  font-size: 250%;
}
h2, h3 { 
  color: #444;
  font-family: Arial, Helvetica, sans-serif;   
  font-weight: lighter;
}
body { 
  margin: 2em; 
}
body, input[text], button { 
  color: #888; 
  font-family: Cambria, Georgia; 
}
a {
  cursor: pointer;
  cursor: hand;
}
button {
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
  cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #aaa; 
  cursor: auto;
}

/* Navigation link styles */
nav a {
  padding: 5px 10px;
  text-decoration: none;
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border-radius: 4px;
}
nav a:visited, a:link {
  color: #607D8B;
}
nav a:hover {
  color: #039be5;
  background-color: #CFD8DC;
}
nav a.router-link-active {
  color: #039be5;
}

/* items class */
.items {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 24em;
}
.items li {
  cursor: pointer;
  position: relative;
  left: 0;
  background-color: #EEE;
  margin: .5em;
  padding: .3em 0;
  height: 1.6em;
  border-radius: 4px;
}
.items li:hover {
  color: #607D8B;
  background-color: #DDD;
  left: .1em;
}
.items li.selected:hover {
  background-color: #BBD8DC;
  color: white;
}
.items .text {
  position: relative;
  top: -3px;
}
.items {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 24em;
}
.items li {
  cursor: pointer;
  position: relative;
  left: 0;
  background-color: #EEE;
  margin: .5em;
  padding: .3em 0;
  height: 1.6em;
  border-radius: 4px;
}
.items li:hover {
  color: #607D8B;
  background-color: #DDD;
  left: .1em;
}
.items li.selected {
  background-color: #CFD8DC;
  color: white;
}

.items li.selected:hover {
  background-color: #BBD8DC;
}
.items .text {
  position: relative;
  top: -3px;
}
.items .badge {
  display: inline-block;
  font-size: small;
  color: white;
  padding: 0.8em 0.7em 0 0.7em;
  background-color: #607D8B;
  line-height: 1em;
  position: relative;
  left: -1px;
  top: -4px;
  height: 1.8em;
  margin-right: .8em;
  border-radius: 4px 0 0 4px;
}

/* everywhere else */
* { 
  font-family: Arial, Helvetica, sans-serif; font-weight: 800
}

select-tab{

  position : absolute;
  height   : 20px;
  left     : 10%;
  right    : 10%;
  top      : 30px;
  background-color: #D2D2D2
}

.handle{
  position : absolute;
  z-index : 3;
  height : 100%;
  outline : 1px solid #888888;
  width : 3px;
  background-color : #1e507d;
}

.handle:hover{

  background-color : black;
  cursor : col-resize;
}

.handle.start{
  margin-left : -4px;
}

.handle.stop{

}

.sequence-zoom-selector, .s-selection{
  position          : absolute;
  top               : 0px;
  height            : 100%;
  z-index           : 3;
}

.sequence-zoom-selector{

  outline           : solid 1px rgba(0,0,0, 0.4);
  background-color  : rgba(0,0,0, 0.2);
  /*  pointer-events    : none; */
}

.s-selection{
  outline           : solid 1px rgba(0,0,0, 0.4);
  background-color  : rgba(0,0,0, 0.2);

}

.s-selection:hover {
  cursor : move;
  outline : solid 1px rgba(0,0,0, 0.7);
  background-color  : rgba(0,0,0, 0.3);
}

.label{
  position : absolute;
  font-size : 12px;
}

.selection{
  bottom : 100%;
}

.sequence{
  top : 100%;
}

.start{
  right : 100%;
}

.stop{
  left : 100%;
}

display-values{
  height: 20px;
  position: absolute;
  top:80px;
  left: 10%;
  right: 10%;
}
### Angular2 Starter Plunker - Typescript - RC.0

A simple plunker demonstrating Angular2 usage:
- Uses SystemJS + TypeScript to compile on the fly
- Includes binding, directives, http, pipes, and DI usage.

For opening 
System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  paths: {
    'npm:': 'https://unpkg.com/'
  },
  //map tells the System loader where to look for things
  map: {
    
    'app': './src',
    
    '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
    '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
    '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
    '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
    '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
    '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
    '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
    
    '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
    '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
    '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
    '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
    '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
    '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
    '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
    
    'rxjs': 'npm:rxjs',
    'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    },
    rxjs: {
      defaultExtension: 'js'
    }
  }
});
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
import {enableProdMode} from '@angular/core';


enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule)
import { Component } from '@angular/core';

import {Element, Values} from './data';
import { LoaderComponent }  from './loader';


@Component({
    selector: 'my-app',
    directives: [LoaderComponent],
    template: ' <loader  [element]="element" ></loader>'
})
export class AppComponent { 

	element: Element;

	constructor(){
		this.element = new Element();
		this.element.name = "test bug";
		for (let i = 0; i < 1000; i++) { 
			let val = new Values();
			val.v = i;

			this.element.dataList.push(val);
		}
	}
}
import {Component, Input, Output } from '@angular/core';
import {Element, Range} from './data';
import { SelectComponent }  from './select';
import { DisplayComponent }  from './display';

@Component({
    selector: 'loader',
    directives: [SelectComponent, DisplayComponent],
    template:  ` 
    <div class="relativeContainer" >
  		<select-tab [selection]="selection" ></select-tab>
  		<display-values [selection]="selection" [element]="element" ></display-values>
    </div>

     `
})

export class LoaderComponent { 

	  @Input() element : Element;
	  selection : Range;

	  constructor(){
	  	this.selection = new Range();
	  	this.selection.start = 0;
	  	this.selection.stop = 1000;
	  }

}
import {Component, Input, Output } from '@angular/core';
import {Element, Range, Values} from './data';
import { PipeFilter }  from './pipe';

@Component({
    selector: 'display-values',
    pipes: [PipeFilter],
    template: `

    	<div class="positionContainer" >
			<svg  width="100%" height="25px" viewBox="0 0 100 1" preserveAspectRatio="none"  >
		    	<g *ngFor="let p of element.dataList  | PipeFilter:selection.start:selection.stop;  let f = first ; let i = index; let l = last   ">
			<rect  [attr.x]="getAnnotationX(p, i, f, l)"  
					height="1" y="0"  
					[attr.width]="blockWidth"
					style="stroke:blue"
				 >
				</rect>
				<text  [attr.x]="getAnnotationTextX(p)" [attr.width]="blockWidth/2"  y="0.7" height=1 fill="#FFFFFF" 
				style="font-size:0.65px; font-width:800;" > {{p.v}} </text>
				</g>
			</svg>          
		</div>
    `
})
export class DisplayComponent { 
	@Input() selection : Range;
	@Input() element : Element;

	elementStartPos: number = 0;
	blockWidth: number = 0;


	getAnnotationX(p: Values, i: number, first: boolean, last : boolean) {

    if(first)
			console.log("first " + i+ " "+p.v);

		if(last)
			console.log("last " + i + " " +p.v);
		this.elementStartPos = this.elementStartPos + this.blockWidth;
		if (i == 0) { 

			this.elementStartPos = 0;
			this.blockWidth = 100 / (this.selection.stop - this.selection.start);
		}
		return this.elementStartPos;
	}
	
	getAnnotationTextX(p: Values){
		let centerTag = 2;	
		if(this.blockWidth <= 4){
			centerTag = 2.2;	
		}
			
		return this.elementStartPos + (this.blockWidth/centerTag) ;
	}
}
import {Component, Input, Output , ElementRef, OnInit } from '@angular/core';
import {Range} from './data';

import {Observable} from "rxjs/Rx"

@Component({
    selector: 'select-tab',
    template: `

    <div class="positionContainer" >
  
  <div class="s-selection"     [style.left]="getSelectionX() + '%'" [style.width]="getSelectionWidth() + '%'" (mousedown)="startMove($event)">
  <span class="label selection start" style="; background-color:white" >{{selection.start}}</span>
  <span class="label selection stop" style="; background-color:white" >{{selection.stop}}</span>
  </div>
  <div class="handle start" [style.left]="getSelectionX() + '%'" (mousedown)="startDragLeft($event)"></div>
  <div class="handle stop"  [style.left]="(getSelectionX() + getSelectionWidth()) +  '%'"  (mousedown)="startDragRight($event)"></div>


  </div>

    `
})
export class SelectComponent implements OnInit{ 
	@Input() selection : Range;
	element: Element;
	root: Element;


	constructor(e : ElementRef){
		this.root = e.nativeElement;
	}

	ngOnInit(){
	    this.element = <Element>this.root;
	}

	getSelectionX() : number{
    	return this.selection.start/ (1000)*100;
  	}
  	getSelectionWidth() : number{
    	return 100* (this.selection.stop - this.selection.start + 1)  /  1000;
  	}

  	startMove(e : MouseEvent){
  			    console.log(this.element)
	    const box = this.element.getBoundingClientRect();
	    const selBox = this.element.getElementsByClassName("s-selection")[0].getBoundingClientRect();
	    const initWidth = selBox.right - selBox.left;
	    const offset = e.clientX - selBox.left;
	    const diff = this.selection.stop - this.selection.start

	    const inputs$ = Observable.fromEvent(window, 'mousemove');
	    const subMM = inputs$.subscribe(
	      (e : MouseEvent) => {
	        const startX = Math.max(Math.min(e.clientX-offset, box.right + 1  - initWidth)  - box.left, 0);
	        const stopX  = startX + initWidth;
	     
	        this.updateSelection(startX, stopX, diff);
	        return false;
	      });

	    const onMouseUp = Observable.fromEvent(window, 'mouseup');
	    const subMU = onMouseUp.subscribe(
	      (e : MouseEvent) => {
	        const startX = Math.max(Math.min(e.clientX-offset, box.right + 1 - initWidth)  - box.left, 0);
	        const stopX  = startX + initWidth;
	        this.updateSelection(startX, stopX, diff);
	        subMM.unsubscribe();
	        subMU.unsubscribe();

	        return false;
	      });

	    return false;
  	}
  	updateSelection(startX : number, stopX : number, diff: number){
	    const box = this.element.getBoundingClientRect();
	   
	    let width = box.width;
	    let ratio = (1000)  / width;

	    this.selection.start = Math.round(startX * ratio);
	    this.selection.stop = this.selection.start + diff; 
  	}
  	startDragRight(e : MouseEvent){
	    const box = this.element.getBoundingClientRect();
	    const selBox = this.element.getElementsByClassName("s-selection")[0].getBoundingClientRect();
	    const offset = e.clientX - selBox.right;

	    // observable of mousemove events
	    const inputs$ = Observable.fromEvent(window, 'mousemove');
	    const subMM = inputs$.subscribe(
	      (e : MouseEvent) => {
	        const stopX = Math.max(Math.min(e.clientX-offset, box.right)  - box.left, selBox.left- box.left+1);
	        this.updateStop(stopX);
	        
	        return false;
	      });

	    const onMouseUp = Observable.fromEvent(window, 'mouseup');
	    const subMU = onMouseUp.subscribe(
	      (e : MouseEvent) => {
	        const stopX = Math.max(Math.min(e.clientX-offset, box.right)  - box.left, selBox.left- box.left+1);
	        this.updateStop(stopX);
	        
	        subMM.unsubscribe();
	        subMU.unsubscribe();
	        return false;
	      });

	    return false;
  }

  startDragLeft(e : MouseEvent){
    const box = this.element.getBoundingClientRect();
    const selBox = this.element.getElementsByClassName("s-selection")[0].getBoundingClientRect();
    const offset = e.clientX - selBox.left;

    const inputs$ = Observable.fromEvent(window, 'mousemove');
    const subMM = inputs$.subscribe(
      (e : MouseEvent) => {
        const startX = Math.max(Math.min(e.clientX-offset, selBox.right-1)  - box.left, 0);
        this.updateStart(startX);
        return false;
      });

    const onMouseUp = Observable.fromEvent(window, 'mouseup');
    const subMU = onMouseUp.subscribe(
      (e : MouseEvent) => {
        const startX = Math.max(Math.min(e.clientX-offset, selBox.right-1)  - box.left, 0);
        this.updateStart(startX);

        subMM.unsubscribe();
        subMU.unsubscribe();
        return false;
      });

    return false;
  }

   updateStart(startX : number){
    const box = this.element.getBoundingClientRect();
    let width = box.width;
    let ratio = (1000)  / width;
    

    if (ratio >= 80 && startX > 100) {
      this.selection.start = Math.round(startX * ratio) + Math.round(ratio / 1.02);
    }
    else {
      this.selection.start = Math.min (Math.max(Math.round(startX * ratio),0),this.selection.stop -1 );      
    }
  }

  updateStop(stopX : number){
    const box = this.element.getBoundingClientRect();
    let width = box.width;
    let ratio = (1000)  / width;   
    

    if (ratio >= 80 && stopX <900) {
      this.selection.stop = Math.round(stopX * ratio) - Math.round(ratio/1.04);
    }
    else {
      this.selection.stop = Math.max(Math.round(stopX * ratio),this.selection.start + 1);
    }
    
  }


}
export class Element {
  name : string;
  dataList : Array<Values>=[]
}
export class Values{
  v : number;
}
export class Range{
  start : number;
  stop : number;
}
import {Injectable, Pipe, PipeTransform} from '@angular/core';

@Pipe({
  name: 'PipeFilter',
  pure: false
})

export class PipeFilter implements PipeTransform {
  
  transform(data: Array<any>, start: number, stop:number){
    console.log('SLICE ON['+start+"-"+stop+"]")
    return data.slice(start, stop)
  }
}
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }  from './app';
import { LoaderComponent }  from './loader';
import { SelectComponent }  from './select';
import { DisplayComponent }  from './display';
import { PipeFilter }  from './pipe';


@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent, LoaderComponent, DisplayComponent, SelectComponent, PipeFilter ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }