ODP Explorer Sample ``` <mark> type="bar" tooltip="true(defaultTo x/y)/{data:[datam.a, datum.b]}" [trigger]="{triggernameX: {type: 'interval', bind:scales} , triggernameY:{on: 'mouseover'}}" [mouseover]="triggername-X? or maybe {name:'triggername-X', clear: true}" [mouseover]="createEvent(name, data?=[], options?= {})" (defines how triggers are going to heppen) color="{field: 'test', inactiveVal='grey'}" [mousedrag]="{type:'interval', clear: true}" triggername-Y="color: {fieldname}" (responding to a trigger) triggername-X="" attr="myAttr" event-y="" stroke="{field: 'test'}" size="{field: 'test'}" </mark> class ParentComponent { init(){ } } class VegaLibrary { parseSpec() { for child in this.vc.children { for attr in child.attr { } } } click (val) { this.myclick.emit(val); } } ``` HTML ``` <chart> <mark type="bar" color="{field: 'test'}" [OnMouseover]="this.barMouseover" event-barMouseover="{color: {field: this.barMouseover.datum}}" > </mark> </chart> ``` TS ``` import {createEvent} from '@labshare/vision-ui'; class CustomVisualization implements OnInit { public barMouseover; public ngOnInit() { this.barMouseover = createEvent(true, {clear=true}); // creating object {datum, options} } this.barMouseover.event.subscribe() => { sort(); } } ``` Vision Framework ``` function createEvent(name: string, datum: boolean, options: any) { return {datum: '', event: Observable}; } const events = [ OnMouseover, OnClick, OnDrag ] class Mark { @Input color?: any; @Input type: string; @Input OnMouseover: any; parseEvents() { for event in events { if(event) { } } } } ``` Step 1: Determine feasiblity of compiler A Vision Framework compiler or template parser needs to be compatible with Angular. Can we create something that can be used both in Anuglar and outside as a standalone? Any compiler/parser we create needs to be run after the Angular lifecycle completes, ngAfterContentChecked (check this), because we need to resolve variables in attributes on html elments. (AfterViewInit is only called once and we might need to re-render the visualizations after change detection.) Running it this way lets angular do the heavy lifing / parsing variables. If we try to implement our own compiler with change detection / variable parsing it could conflict with angular's template variables, input/output properties, and text binding and would need to sync up with its change detection. As the names in the template must resolve to objects in typescript, their scope is limitied to the framework and not the consuming parent. References can be provided via the framework's api to consuming components. Otherwise, if we parse before the view is initialized, we will have to resolve all variables ourselves which is a thing many other frameworks have acheived and for this work, Angular has optimized. Step 2: Framework Design Objects used will be instantiated within the framework, be made accessible to the parent components through the framework, and names will be inferred from use on the template. This way the user can 1) refrence the objects in html, 2) have the framework wire up appropriate elements, 3) provide the parent access to events and broadcasted data for external use. It appears the only way to pass custom attributes and their values on html elements is to use `[attr.customValue]` syntax. This binding was created to change attributes on html, not pass data between components so it has its limitations. Only values and primitive object types can be passed this way. Including complex objects results in a parsed value of `[object Object]`. in Json objects provided in the template can only be provided as a json string to be parsed via JSON.parse method. For any use of variables Scenarios: 1) Well know attributes: `click, mouseover` Following the definitions from above, if you want to use a variable for any custom attribute i.e. `event-barMouseover` you would have to use the attr binding for angular: `[attr.event-barMouseover]` [How Anguar handles property binding](https://blog.bitsrc.io/one-way-property-binding-mechanism-in-angular-f1b25cf00de7#:~:text=Property%20binding%20is%20the%20primary,in%20brackets%3A%20%5Bproperty%5D%20.&text=The%20src%20property%20of%20the,srcURL%20property%20of%20the%20class.) Another method would be to use angular comonent output param binding having another layer (can't do this because you need a reference for the response and trigger) Html ``` //Broadcasts data from child, to retrieve data externally <mark (myclick)="myfunction()"> </mark> //Input property to be handled by mark component <mark [myclick]="myTriggerKeyPassToComponent" > // </mark> //Updates dom attribtue that can be accessed by ViewChild <mark [attr.myclick]="valueOrPrimative" > </mark> //Static dom attribute accessible to ViewChild <mark myclick="noDynamicValue" > </mark> ``` You need to have key value in response attribute: ``` <chart> <mark type="bar" color="{field: 'test'}" [OnMouseover]="barMouseoverName" [response]="{name: barMouseoverName, value: {color: {field: this.barMouseover.datum}}}" > </mark> </chart> ``` TS ``` class CustomVisualization { public barMouseoverName: string; public barMosueover: VisionEvent; public ngOnInit(){ this.barMouseover = getEvent(barMouseoverName); } } class MarkComponent{ @Output() myclick: EventEmitter; constructor(){ const name = this.getName(); } } ``` or maybe ``` <chart> <mark type="bar" color="{field: 'test'}" [OnMouseover]="barMouseover" [response]="{eventObj: barMouseover, value: {color: {field: this.barMouseover.datum}}}" > </mark> </chart> ``` TS ``` class CustomVisualization { public barMosueover: VisionEvent; public ngOnInit(){ this.barMouseover = getEvent('myname'); } } ``` What is barMouseover object going to be used for? Why does the parent component need to access it? In Vega it is key that is used to link an event to a result. Do we want to be able to perform some operation on that link? Pass it around? You can pass an output object instead