/** * Created by mm28969 on 3/9/17. */ import * as d3 from "d3"; import {getChartMouseLocation} from "../mmviz-common/index"; import {Dispatcher} from "../mmviz-dispatch/index"; import {DetailsComponent} from "../mmviz-component-dom/index"; export enum DetailsPositionTypeEnum { ABOVE = 1, OFF_CENTER, } export enum DetailsFocusTypeEnum { MOUSE = 1, DATA, } /** * set up the supported UI behaviors for details window, which is a hover over pop up window. * such as: * how mouse behavior (over, move, out) affects the window display * if details hover over window should have color block similar to legend */ export class DetailsBehavior { chartSelector; componentSelector; focusTypeEnum; positionTypeEnum; detailsComponent: DetailsComponent; hasFocus; hasMouseOver; hasMouseMove; hasMouseOut; hasColorIcon; // indicate if the color icon would be shown in the details hover over window constructor(chartSelector, componentSelector){ this.chartSelector = chartSelector; this.componentSelector = componentSelector; this.focusTypeEnum = DetailsFocusTypeEnum.MOUSE; this.positionTypeEnum = DetailsPositionTypeEnum.ABOVE; this.detailsComponent = new DetailsComponent(this.chartSelector + " .chart-details"); this.hasFocus = true; this.hasMouseOver = true; this.hasMouseMove = true; this.hasMouseOut = true; this.hasColorIcon = false; // to add the color icon in details window, update this value to true when initiate builderSVG instance } set templateRenderer(renderer){ this.detailsComponent.detailsTemplate.renderer = renderer; } setupBehavior(){ let dispatcher: Dispatcher = Dispatcher.getInstance(), container = d3.select(this.chartSelector + " .chart-viz"), dispatcherKey = `${this.chartSelector}_${this.componentSelector}` ; this.detailsComponent.createView(); window.addEventListener("keydown", (e) => { // escape key if (e.which === 27){ this.detailsComponent.hide(); } }); dispatcher.subscribe("focus", dispatcherKey, (payload) => { if (!this.hasFocus){ return; } if ( payload.parentSelector === this.chartSelector && payload.selector === this.componentSelector && payload.d.details ) { let location = payload.location; if (!location){ let bBox = payload.event.target.getBBox(); location = {x: bBox.x + (0.5 * bBox.width), y: bBox.y + (0.5 * bBox.height)}; } this.detailsComponent.updateView({ hasColorIcon: this.hasColorIcon, data: payload.d // the single dLayout obj for one visual element, will contain details string, color, and other attributes }); if (this.positionTypeEnum === DetailsPositionTypeEnum.ABOVE){ this.detailsComponent.updatePositionAbove(location, container); } else { this.detailsComponent.updatePositionOffCenter(location, container); } this.detailsComponent.show(); } }); /** * The Details component subscribes to mouse interaction action messages, via the Dispatcher. * Here defines the call back function taken after the mouse behaviors are activated. * payload accepted by the call back function is a JS object, representing data for one visual element, such a bar, * payload contains attributes defined in getEventPayload() from mmviz-component-svg/components.ts, such as * - parentSelector * - selector * - event: d3 event * - i: index * - d: one dLayout obj from viewModel.dataArray return from layoutDatum function in layoutCreator class (under mmviz-layout folder) * (please refer to individual component ts file, component.ts under mmviz-component-svg to know more about * Dispatcher behaviors, call back function parameters, etc) */ dispatcher.subscribe("mouseover", dispatcherKey, (payload) => { if (!this.hasMouseOver){ return; } if ( payload.parentSelector === this.chartSelector && payload.selector === this.componentSelector && payload.d.details ) { let location = payload.location; if (!location || this.focusTypeEnum === DetailsFocusTypeEnum.MOUSE){ location = getChartMouseLocation(this.chartSelector, payload.event); } // this.detailsComponent.updateView(payload.d.details); this.detailsComponent.updateView({ hasColorIcon: this.hasColorIcon, data: payload.d // the single dLayout obj for one visual element, will contain details string, color, and other attributes }); if(this.positionTypeEnum === DetailsPositionTypeEnum.ABOVE){ this.detailsComponent.updatePositionAbove(location, container); } else { this.detailsComponent.updatePositionOffCenter(location, container); } this.detailsComponent.show(); } }); dispatcher.subscribe("mousemove", dispatcherKey, (payload) => { if (!this.hasMouseMove){ return; } if ( payload.parentSelector === this.chartSelector && payload.selector === this.componentSelector && payload.d.details ) { let location = payload.location; if(!location || this.focusTypeEnum === DetailsFocusTypeEnum.MOUSE){ location = getChartMouseLocation(this.chartSelector, payload.event); } this.detailsComponent.updateView({ hasColorIcon: this.hasColorIcon, data: payload.d }); if (this.positionTypeEnum === DetailsPositionTypeEnum.ABOVE){ this.detailsComponent.updatePositionAbove(location, container); } else { this.detailsComponent.updatePositionOffCenter(location, container); } } }); dispatcher.subscribe("mouseout", dispatcherKey, (payload) => { if (!this.hasMouseOut){ return; } if ( payload.parentSelector === this.chartSelector && payload.selector === this.componentSelector ) { this.detailsComponent.hide(); } }); } }