/** * График. * this.props.datum - данные в формате D3 */ var NvLineChart = React.createClass({ chart: null, d3ChartData: null, /*--------------------*/ render: function(){return( ce('div', {id: 'chart'}, ce('svg', {style: {'height': '500px'}})) )}, componentDidMount: function() { var _this = this; nv.addGraph(function() { _this.chart = nv.models.lineChart().useInteractiveGuideline(true); _this.chart.xAxis.axisLabel('Time').tickFormat(function(d){ return d3.time.format('%X')(new Date(d)); }); _this.chart.yAxis.axisLabel('Players').tickFormat(d3.format('d')); _this.d3ChartData = d3.select('#chart svg').datum(_this.props.datum); _this.d3ChartData.transition().duration(500).call(_this.chart); nv.utils.windowResize(_this.chart.update); return _this.chart; }); }, componentDidUpdate: function() { if (this.d3ChartData === null) return; this.d3ChartData.datum(this.props.datum); this.d3ChartData.transition().duration(500).call(this.chart); nv.utils.windowResize(this.chart.update); }, componentWillUnmount: function() { var nvtooltip = document.querySelector('div[class~="nvtooltip"]'); if (nvtooltip !== null) { nvtooltip.parentElement.removeChild(nvtooltip) } } }); var Tabs = React.createClass({ onTabClick: function(idx){ this.setState({ activeTab: idx }); }, /*--------------------*/ getInitialState: function(){return{ activeTab: 0 }}, render: function(){ var _this = this; var tabsElm = []; this.props.tabs.forEach(function(title, i){ tabsElm.push(ce('li', (i === _this.state.activeTab ? {className: 'active'} : null), ce('a', {href: '#tab'+(i+1), onClick: _this.onTabClick.bind(_this, i)}, title))); }); var showElement = this.props.children.map(function(child, i){ return ce('div', (i !== _this.state.activeTab ? {style: {display: 'none'}} : null), child); }); return(ce('div', null, ce('ul', {className: 'nav nav-tabs', id: 'tabs'}, tabsElm), showElement )) }, componentDidUpdate: function() { if (this.props.stateCallback !== null) { this.props.stateCallback(this.state.activeTab); } } }); var WebConsole = React.createClass({ ws: null, connect: function(){ if (this.ws !== null) return; var _this = this; this.ws = new WebSocket("ws://127.0.0.1:8770"); //FIXME указывать ip:port из настроек this.ws.onopen = function(){ console.debug('WS: open...'); }; this.ws.onclose = function(){ console.debug('WS: close...'); }; this.ws.onerror = function(e){ console.debug('WS: error'); console.error(e); }; this.ws.onmessage = function(event){ _this.setState({ lines: _this.state.lines.concat([event.data]) }); //TODO необходимо ограничить кол-во строк }; }, disconnect: function() { if (this.ws === null) return; this.ws.close(); this.ws = null; }, /*--------------------*/ getInitialState: function(){return{ lines: [] }}, render: function(){ var ansi_up = new AnsiUp; return( ce('div', {id: 'webconsole'}, ce('div', {className: 'output'}, this.state.lines.map(function(line){ return ce('p', {dangerouslySetInnerHTML: {__html: ansi_up.ansi_to_html(line)}}); }) ), ce('input') ) ) }, componentWillUnmount: function(){ this.disconnect(); } }); var ServerInfo = React.createClass({ tabStateWebConsole: function(state) { if (state === 1) { this.refs.webconsole.connect(); } }, /*--------------------*/ getInitialState: function(){return { title: null, data: [] }}, render: function(){ if (this.state.title === null) { return ce('div', null, 'no data'); } else { return( ce('div', null, ce('h2', {style: {'margin-top': '0px'}}, this.state.title), ce(Tabs, {tabs: ['Онлайн', 'Консоль'], stateCallback: this.tabStateWebConsole}, ce(NvLineChart, {datum: [{ key: 'Online players', color: '#37d668', area: true, values: this.state.data }]}), ce(WebConsole, {ref: 'webconsole'}) ) ) ) } } }); /** * Пункт списка серверов. * this.props.title - заголовок / clientId * this.props.onClick - callback события клика * this.props.active - состояние активности (true/false) */ var ServerListItem = React.createClass({ render: function(){ return( ce('a', {className: 'list-group-item clearfix' + (this.props.active ? ' active' : ''), href: '#', onClick: this.props.onClick}, ce('span', {style: {'padding-top': '15px'}}, ce('span', {className: 'glyphicon glyphicon-tasks'}), nbsp, this.props.title ) ) ) } }); var ServerList = React.createClass({ render: function(){return( ce('div', {className: 'list-group'}, this.props.children) )} });