Mercurial > hg > ugly-duckling
changeset 394:f45a916eb5b1
Use the cross hair layer for notes, tracks and curve. This involved bodging in unit to ShapedFeatureData, which isn't particularly easy to do because this isn't an encapsulated type. Need to come back to improving this, as I am monkey-patching a unit property onto Arrays etc.
author | Lucas Thompson <dev@lucas.im> |
---|---|
date | Thu, 01 Jun 2017 18:55:55 +0100 |
parents | a02e6ec4a9d2 |
children | de9864aeacf0 |
files | src/app/analysis-item/analysis-item.component.html src/app/visualisations/FeatureUtilities.ts src/app/visualisations/curve/curve.component.ts src/app/visualisations/notes/notes.component.ts src/app/visualisations/waves-base.component.ts |
diffstat | 5 files changed, 83 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/src/app/analysis-item/analysis-item.component.html Thu Jun 01 16:26:52 2017 +0100 +++ b/src/app/analysis-item/analysis-item.component.html Thu Jun 01 18:55:55 2017 +0100 @@ -40,7 +40,7 @@ [onSeek]="onSeek" [curve]="item.collected" ></ugly-curve> - <ugly-vertical-scale *ngSwitchCase="'tracks'"> + <ugly-cross-hair-inspector *ngSwitchCase="'tracks'"> <ugly-tracks [colour]="getNextColour()" [timeline]="timeline" @@ -48,8 +48,8 @@ [onSeek]="onSeek" [tracks]="item.collected" ></ugly-tracks> - </ugly-vertical-scale> - <ugly-vertical-scale *ngSwitchCase="'notes'"> + </ugly-cross-hair-inspector> + <ugly-cross-hair-inspector *ngSwitchCase="'notes'"> <ugly-notes [colour]="getNextColour()" [timeline]="timeline" @@ -57,7 +57,7 @@ [onSeek]="onSeek" [notes]="item.collected" ></ugly-notes> - </ugly-vertical-scale> + </ugly-cross-hair-inspector> <ugly-instants *ngSwitchCase="'instants'" [colour]="getNextColour()"
--- a/src/app/visualisations/FeatureUtilities.ts Thu Jun 01 16:26:52 2017 +0100 +++ b/src/app/visualisations/FeatureUtilities.ts Thu Jun 01 18:55:55 2017 +0100 @@ -74,17 +74,19 @@ type ShapeDeducedFromList = 'instants' | 'notes'; export type HigherLevelFeatureShape = CollectedShape | ShapeDeducedFromList; -export type ShapedFeatureData = VectorFeature +export type ShapedFeatureData = {unit?: string} & ( + VectorFeature | MatrixFeature | TracksFeature | Note[] - | Instant[]; + | Instant[] + ); // These needn't be classes (could just be interfaces), just experimenting export abstract class ShapedFeature<Shape extends HigherLevelFeatureShape, - Data extends ShapedFeatureData> { + Data extends ShapedFeatureData & {unit?: string}> { shape: Shape; - collected: Data; + collected: Data & {unit?: string}; } export class Vector extends ShapedFeature<'vector', VectorFeature> {} @@ -143,32 +145,46 @@ export function toKnownShape(response: SimpleResponse): KnownShapedFeature { const deducedShape = deduceHigherLevelFeatureShape(response); - switch (deducedShape) { - case 'vector': - return response.features as Vector; - case 'matrix': - return response.features as Matrix; - case 'tracks': - return response.features as Tracks; - case 'notes': - return { - shape: deducedShape, - collected: mapFeaturesToNotes( + const shaped: KnownShapedFeature | null = (() => { + switch (deducedShape) { + case 'vector': + return response.features as Vector; + case 'matrix': + return response.features as Matrix; + case 'tracks': + return response.features as Tracks; + case 'notes': + // TODO refactor + const notes: Note[] & {unit?: string} = mapFeaturesToNotes( response.features.collected as FeatureList, response.outputDescriptor - ) - }; - case 'instants': - const featureData = response.features.collected as FeatureList; - return { - shape: deducedShape, - collected: featureData.map(feature => ({ - time: toSeconds(feature.timestamp), - label: feature.label - })) - }; + ); + notes.unit = 'MIDI'; + return { + shape: deducedShape, + collected: notes, + }; + case 'instants': + const featureData = response.features.collected as FeatureList; + return { + shape: deducedShape, + collected: featureData.map(feature => ({ + time: toSeconds(feature.timestamp), + label: feature.label + })) + }; + } + })(); + const unit = response.outputDescriptor.configured.unit; + if (shaped) { + const bodgeUnit = (shaped: KnownShapedFeature) => { + (shaped.collected as any).unit = unit; + return shaped; + }; + return unit && !shaped.collected.unit ? bodgeUnit(shaped) : shaped; + } else { + throwShapeError(); } - throwShapeError(); } export interface PlotData {
--- a/src/app/visualisations/curve/curve.component.ts Thu Jun 01 16:26:52 2017 +0100 +++ b/src/app/visualisations/curve/curve.component.ts Thu Jun 01 18:55:55 2017 +0100 @@ -7,7 +7,7 @@ Input } from '@angular/core'; import {OnSeekHandler} from '../../playhead/PlayHeadHelpers'; -import {VectorFeature} from 'piper/HigherLevelUtilities'; +import {TracksFeature, VectorFeature} from 'piper/HigherLevelUtilities'; @Component({ selector: 'ugly-curve', @@ -17,7 +17,7 @@ [width]="width" [onSeek]="onSeek" [colour]="colour" - [tracks]="[curve]" + [tracks]="tracks" ></ugly-tracks> </ugly-cross-hair-inspector>`, changeDetection: ChangeDetectionStrategy.OnPush @@ -26,6 +26,13 @@ @Input() timeline: Timeline; // TODO refactor WaveComponents to have own Timeline, sharing a TimeContext @Input() onSeek: OnSeekHandler; @Input() width: number; - @Input() curve: VectorFeature; + @Input() set curve(curve: VectorFeature & {unit?: string}) { + const tempTracks: TracksFeature & {unit?: string} = [curve]; + tempTracks.unit = curve.unit; + this.tracks = tempTracks; + } + + private tracks: TracksFeature & {unit?: string}; + @Input() colour: string; }
--- a/src/app/visualisations/notes/notes.component.ts Thu Jun 01 16:26:52 2017 +0100 +++ b/src/app/visualisations/notes/notes.component.ts Thu Jun 01 18:55:55 2017 +0100 @@ -2,9 +2,10 @@ * Created by lucast on 31/05/2017. */ import { + InspectableVerticallyBoundedComponent, VerticallyBounded, - VerticallyBoundedWavesComponent, - VerticalScaleRenderer + VerticalScaleRenderer, + VerticalValueInspectorRenderer } from '../waves-base.component'; import { ChangeDetectionStrategy, @@ -21,10 +22,11 @@ changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: VerticallyBounded, useExisting: NotesComponent }, - { provide: VerticalScaleRenderer, useExisting: NotesComponent } + { provide: VerticalScaleRenderer, useExisting: NotesComponent }, + {provide: VerticalValueInspectorRenderer, useExisting: NotesComponent } ] }) -export class NotesComponent extends VerticallyBoundedWavesComponent<Note[]> { +export class NotesComponent extends InspectableVerticallyBoundedComponent<Note[]> { private currentVerticalRange: [number, number]; get range(): [number, number] {
--- a/src/app/visualisations/waves-base.component.ts Thu Jun 01 16:26:52 2017 +0100 +++ b/src/app/visualisations/waves-base.component.ts Thu Jun 01 18:55:55 2017 +0100 @@ -22,7 +22,7 @@ export abstract class VerticalValueInspectorRenderer extends VerticalScaleRenderer { // TODO how do I know these layers are actually 'describable'? - abstract renderInspector(range: [number, number]): void; + abstract renderInspector(range: [number, number], unit?: string): void; } export abstract class WavesComponent<T extends ShapedFeatureData | AudioBuffer> @@ -209,8 +209,10 @@ @Input() set onSeek(handler: OnSeekHandler) { this.wrappedSeekHandler = (x: number) => { handler(x); - this.highlight.currentPosition = x; - this.highlight.update(); + if (this.highlight) { + this.highlight.currentPosition = x; + this.highlight.update(); + } }; } @@ -219,18 +221,20 @@ } - renderInspector(range: [number, number]): void { - this.highlight = new Waves.helpers.HighlightLayer( - this.cachedFeatureLayers, - { - opacity: 0.7, - height: this.height, - color: '#c33c54', // TODO pass in? - labelOffset: 38, - yDomain: range, - unit: ''// TODO - } - ); - this.addLayer(this.highlight); + renderInspector(range: [number, number], unit?: string): void { + if (range) { + this.highlight = new Waves.helpers.HighlightLayer( + this.cachedFeatureLayers, + { + opacity: 0.7, + height: this.height, + color: '#c33c54', // TODO pass in? + labelOffset: 38, + yDomain: range, + unit: unit || this.feature.unit || '' + } + ); + this.addLayer(this.highlight); + } } }