Introdução
O Dashboard Personalizado (Generic Dashboard) é uma ferramenta que permite montar dashboards de acordo com a necessidade dos clientes sem a intervenção do Core. Nessa ferramenta são usados os componentes HighCharts, responsável pela geração dos gráficos e o gridstack.js para a organização do Layout, possibilitando:
- Cria Dashboards específicos e seus respectivos gráficos;
- Obter dados específicos usando consultas anônimas (não foi adotada a classe EntryPoint do NFS Core);
- Salvar as configuração dos gráficos, permitindo alterá-los a qualquer momento;
- Montar Gráficos usando as configurações e os dados obtidos;
- Permitir alterar a disposição/tamanho dos gráficos.
Pré-requesitos
São pré-requisitos para esse módulo:
- Módulo "Rotas Personalizada" habilitado e rota personalizada para "/custom/genericDashboad/" criada (veja como);
- Tabelas "nfs_generic_dashboard" e "nfs_generic_chart" criadas na seguinte estrutura:
CREATE TABLE `nfs_generic_dashboard` (
`SEQ_DB` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`EMPRESA` int(11) DEFAULT NULL,
`FILIAL` int(11) DEFAULT NULL,
`LOCAL` int(11) DEFAULT NULL,
`TITLE` varchar(100) DEFAULT NULL,
`FILTERS` text,
`OPTIONS` text,
`LAYOUT` text,
`ENABLED` int(1) DEFAULT '1',
UNIQUE KEY `SEQ_DB_UNIQUE` (`SEQ_DB`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
CREATE TABLE `nfs_generic_chart` (
`SEQ_DB` bigint(20) NOT NULL AUTO_INCREMENT,
`DASHBOARD_SEQ_DB` bigint(20) NOT NULL,
`EMPRESA` int(11) NOT NULL,
`FILIAL` int(11) NOT NULL,
`LOCAL` int(11) NOT NULL,
`TITLE` varchar(100) NOT NULL,
`CONFIG` text NOT NULL,
`FILTERS` text,
`QUERIES` text,
`INS_DH` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`ENABLED` int(11) DEFAULT '1',
`DELETED` int(11) DEFAULT '0',
`OPTIONS` json NULL,
`TYPE` enum('H','E','G') DEFAULT 'H',
`CHART_ORDER` int(11) DEFAULT 999 NULL,
UNIQUE KEY `SEQ_DB_UNIQUE` (`SEQ_DB`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
Configurações Iniciais
Tabela nfs_generic_dashboard
Possui as definições principais do dashboard, sendo:
- TITLE: Título do Dashboard exibido no topo do módulo;
TITLE='Generic Dashboard'
- FILTERS: JSON com definições dos filtros;
{
"inicio": {
"type": "Date",
"options": {
"label": "De",
"required": false,
"language": "pt-BR"
}
},
"fim": {
"type": "Date",
"options": {
"label": "Até",
"required": false,
"language": "pt-BR"
}
},
"equipamento": {
"type": "Table",
"options": {
"label": "Equipamento",
"required": true,
"multiple": true
}
}
}
-
OPTIONS: coluna criada para futuras personalizações.
-
LAYOUT: coluna usada para salvar as definições de layout através do gridstack.js.
Tabela nfs_generic_chart
Tabela usada para armazenar as configurações dos gráficos dos dashboards, sendo:
- DASHBOARD_SEQ_DB: FK da tabela nfs_generic_dashboard;
DASHBOARD_SEQ_DB=1
- TITLE: Título do Gráfico;
TITLE='Generic Dashboard'
- CONFIG: Configuração do gráfico, variando de acordo com o tipo e opções do gráfico;
{
"chart": {
"type": "bar"
},
"title": {
"text": "Atividades por Modelos"
},
"xAxis": {
"categories": this.vals.categories
},
"yAxis": {
"min": 0,
"title": {
"text": "Atividades por Modelos"
}
},
"legend": {
"reversed": true
},
"plotOptions": {
"series": {
"stacking": "normal"
}
},
"series": this.vals.series
}
'
Os valores expressos por this.vals.categories e this.vals.series são usando como placeholders dentro das configurações do gráfico. Eles serão substituídos por dados obtidos das queries do gráfico. Todos os placeholders devem usar o préfixo "this.vals", seguido do nome da série, p.e. this.vals.<nome-da-serie>, sempre atentando para caixa baixa. As definições dos placeholders serão definidos na coluna QUERIES mais adiante. {.is-danger}
- FILTERS: JSON com definições dos filtros (similar ao usado em nfs_generic_dashboard, exceto que filtra apenas o gráfico ao qual pertence);
{
"inicio": {
"type": "Date",
"options": {
"label": "De",
"required": false,
"language": "pt-BR"
}
},
"fim": {
"type": "Date",
"options": {
"label": "Até",
"required": false,
"language": "pt-BR"
}
},
"equipamento": {
"type": "Table",
"options": {
"label": "Equipamento",
"required": true,
"multiple": true
}
}
}
- QUERIES: JSON contendo as definições dos placeholders especificados na coluna CONFIG (no exemplo, this.vals.categories e this.vals.series). Obs: Formato abaixo não é recomendado.
{
"categories": {
"CODE_TYPE": "PHP",
"CONTENT": "$user = \\core\\xDS::getUser();\r\n$empresa = $user->EMPRESA_ATUAL;\r\n$local = $user->LOCAL_ATUAL;\r\n$filial = $user->FILIAL_ATUAL;\r\n$timezone = $this->user->TIMEZONE ?? date_default_timezone_get();\r\n\r\n$dIni = (empty($inicio)) ? new DateTime('-2 months', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\\/m\\/Y', $inicio);\r\n$dFim = (empty($fim)) ? new DateTime('now', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\\/m\\/Y', $fim);\r\n$comeco = date_format($dIni,'Y-m-d');\r\n$final = date_format($dFim,'Y-m-d');\r\n\r\nif (!empty($modelo)) {\r\n\t$modelos = (is_array($modelo)) ? ' and m.SEQ_DB in (' . implode(',', $modelo) . ') ' : \" and m.SEQ_DB = {$modelo} \";\r\n} else {\r\n\t$modelos = '';\t\r\n}\r\n\r\n$sql = \"SELECT \r\n\tdistinct m.DESCRICAO Modelo\r\n\tFROM app_apontamento_maquina a\r\n\tINNER JOIN app_equipamento e ON a.EQUIPAMENTO_SEQ_DB = e.SEQ_DB\r\n\tINNER JOIN app_modelo m ON e.MODELO_SEQ_DB = m.SEQ_DB\r\n\tWHERE DATE(a.INI_DH) between '{$comeco}' and '{$final}' \r\n\tand a.empresa = {$empresa} and a.local in ({$local},9999) and a.filial in ({$filial},9999) and a.ativo = 1 and a.deleted = 0\r\n\t{$modelos} GROUP BY m.SEQ_DB;\";\r\n\r\n$todosModelos = \\core\\ConexaoDB::query($sql, $params = []);\r\n$series = [];\r\nforeach ($todosModelos as $model){\r\n\tarray_push($series,$model['Modelo']);\r\n}\r\nreturn $series;"
},
"series": {
"CODE_TYPE": "PHP",
"CONTENT": "$user = \\core\\xDS::getUser();\r\n$empresa = $user->EMPRESA_ATUAL;\r\n$local = $user->LOCAL_ATUAL;\r\n$filial = $user->FILIAL_ATUAL;\r\n\r\n$timezone = $this->user->TIMEZONE ?? date_default_timezone_get();\r\n$dIni = (empty($inicio)) ? new DateTime('-2 months', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\\/m\\/Y', $inicio);\r\n$dFim = (empty($fim)) ? new DateTime('now', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\\/m\\/Y', $fim);\r\n$comeco = date_format($dIni,'Y-m-d');\r\n$final = date_format($dFim,'Y-m-d');\r\n\r\nif (!empty($modelo)) {\r\n\t$modelos = (is_array($modelo)) ? ' and m.SEQ_DB in (' . implode(',', $modelo) . ') ' : \" and m.SEQ_DB = {$modelo} \";\r\n} else {\r\n\t$modelos = '';\t\r\n}\r\n\r\n$series = [];\r\n$tipoAtividades = \"SELECT\r\n\tDISTINCT (case when (ati.FLAG_PRODUTIVA = 1) then 'Produtiva' \r\n\twhen (ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 0 AND ati.FLAG_ABASTECIMENTO = 0 AND ga.FLAG_PARADA_PROCESSO = 0 AND ga.FLAG_PARADA_OPERACIONAL = 0) then 'Improdutiva' \r\n\twhen (ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 1 AND ati.FLAG_ABASTECIMENTO = 0 AND ga.FLAG_PARADA_PROCESSO = 0 AND ga.FLAG_PARADA_OPERACIONAL = 0) then 'Paradas de Manutencao'\r\n\twhen (ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 0 AND ati.FLAG_ABASTECIMENTO = 1 AND ga.FLAG_PARADA_PROCESSO = 0 AND ga.FLAG_PARADA_OPERACIONAL = 0) then 'Abastecimento'\r\n\twhen (ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 0 AND ati.FLAG_ABASTECIMENTO = 0 AND ga.FLAG_PARADA_PROCESSO = 1 AND ga.FLAG_PARADA_OPERACIONAL = 0) then 'Paradas de Processo'\r\n\twhen (ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 0 AND ati.FLAG_ABASTECIMENTO = 0 AND ga.FLAG_PARADA_PROCESSO = 0 AND ga.FLAG_PARADA_OPERACIONAL = 1) then 'Paradas Operacionais'\r\n\tEND) Atividades\r\n\tFROM app_apontamento_maquina a\r\n\tINNER JOIN app_equipamento e ON a.EQUIPAMENTO_SEQ_DB = e.SEQ_DB\r\n\tINNER JOIN app_modelo m ON e.MODELO_SEQ_DB = m.SEQ_DB\r\n\tINNER JOIN app_atividade ati ON a.ATIVIDADE_SEQ_DB = ati.SEQ_DB\r\n\tINNER JOIN app_grupo_atividade ga ON ati.GRUPO_ATIVIDADE_SEQ_DB = ga.SEQ_DB\r\n\tWHERE DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}' and a.empresa = {$empresa} and a.local in ({$local},9999) and a.filial in ({$filial},9999) and a.ativo = 1 and a.deleted = 0\r\n {$modelos};\";\r\n\r\n$grupoAtividades = \\core\\ConexaoDB::query($tipoAtividades);\r\nforeach ($grupoAtividades as $Atividades){\r\n\tif ($Atividades['Atividades'] == 'Abastecimento') {\r\n\t\tcontinue;\r\n\t} else {\r\n\t\t$valores['name'] = [];\r\n\t\t$valores['data'] = [];\r\n\t\t$valores['name'] = $Atividades['Atividades'];\r\n\t\t$variavel = $Atividades['Atividades'];\r\n\t\t$dados = \"\r\n\t\tSELECT DISTINCT m.DESCRICAO fabricante, \r\n\t\t\tif('{$Atividades['Atividades']}' = 'Produtiva',(SUM(IF(ati.FLAG_PRODUTIVA = 1,a.INI_FIM_DIFF_SEC,0))/ SUM(IF(DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}', a.INI_FIM_DIFF_SEC,0)))*100,0)'Produtiva',\r\n\t\t\tif('{$Atividades['Atividades']}' = 'Improdutiva',(SUM(IF(ati.FLAG_PRODUTIVA = 0 AND ati.FLAG_MANUTENCAO = 0 AND ati.FLAG_ABASTECIMENTO = 0 AND ga.FLAG_PARADA_PROCESSO = 0 AND ga.FLAG_PARADA_OPERACIONAL = 0,a.INI_FIM_DIFF_SEC,0))/ SUM(IF(DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}', a.INI_FIM_DIFF_SEC,0)))*100,0) 'Improdutiva',\r\n\t\t\tif('{$Atividades['Atividades']}' = 'Paradas de Processo',(SUM(IF(ga.FLAG_PARADA_PROCESSO = 1,a.INI_FIM_DIFF_SEC,0))/ SUM(IF(DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}', a.INI_FIM_DIFF_SEC,0)))*100,0) 'Paradas de Processo', \r\n\t\t\tif('{$Atividades['Atividades']}' = 'Paradas Operacionais',(SUM(IF(ga.FLAG_PARADA_OPERACIONAL = 1,a.INI_FIM_DIFF_SEC,0))/ SUM(IF(DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}', a.INI_FIM_DIFF_SEC,0)))*100,0) 'Paradas Operacionais', \r\n\t\t\tif('{$Atividades['Atividades']}' = 'Paradas de Manutencao',(SUM(IF(ati.FLAG_MANUTENCAO = 1,a.INI_FIM_DIFF_SEC,0))/ SUM(IF(DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}', a.INI_FIM_DIFF_SEC,0)))*100,0) 'Paradas de Manutencao'\r\n\t\t\tFROM app_apontamento_maquina a\r\n\t\t\tINNER JOIN app_equipamento e ON a.EQUIPAMENTO_SEQ_DB = e.SEQ_DB\r\n\t\t\tINNER JOIN app_modelo m ON e.MODELO_SEQ_DB = m.SEQ_DB\r\n\t\t\tINNER JOIN app_atividade ati ON a.ATIVIDADE_SEQ_DB = ati.SEQ_DB\r\n\t\t\tINNER JOIN app_grupo_atividade ga ON ati.GRUPO_ATIVIDADE_SEQ_DB = ga.SEQ_DB\r\n\t\t\tWHERE DATE(a.INI_DH) BETWEEN '{$comeco}' AND '{$final}' and a.empresa = {$empresa} and a.local in ({$local},9999) and a.filial in ({$filial},9999) and a.ativo = 1 and a.deleted = 0\r\n{$modelos} GROUP BY m.SEQ_DB;\";\r\n\r\n\t\t$dadosSomados = \\core\\ConexaoDB::query($dados);\r\n\t\tforeach ($dadosSomados as $resultados){\r\n\t\t\tarray_push($valores['data'], floatval($resultados[$variavel]));\r\n\t\t}\r\n\t\tarray_push($series, $valores);\r\n\t}\r\n}\r\nreturn $series;"
}
}
Onde:
- Cada série refere-se a um placeholder na configuração;
- CODE_TYPE: tipo de interpretação dos dados. Entre as interpretações estão;
- CONST: retorna apenas um valor, sendo constante (número, string, boleano) ou variável;
- PHP: bloco de código PHP para obtenção dos dadostrução de código.
Exemplo com CODE_TYPE = ENTRY_POINT
/*
Dados enviados pelo core:
$entryPointsDashboards->param = $filtersConfigAndValues;
$entryPointsDashboards->parameters = $filtersConfigAndValues;
$entryPointsDashboards->param['inputValues'] = $filtersConfigAndValues;
$entryPointsDashboards->processEntryPoint();
O core recebe a propriedade 'data' para enviar ao gráfico JS:
$returnContent = $entryPointsDashboards->data;
*/
$this->queryData['apontamentosPorHora'] = $apontamentosPorHora;
$this->queryData['apontamentos'] = $apontamentosList;
$this->queryData['equipamentos'] = $equipamentos;s. É possível acessar o resultado dos filtros aplicados.
3. JSON: Retora um JSON válido
4. ENTRY_POINT: Executa um Entry Point DASHBOARD com nome = CHART.NAME
- **CONTENT**: o valor ou nome da variável (se o **CODE_TYPE** for **CONST**) ou o bloco de in
- CHART_ORDER: INT que irá armazenar a posição padrão do grafico dentro do dashboard, sendo o valor 1 para o topo da exibição, 2 para a segunda posição e assim por diante, o campo tem inicialmente o valor padrão de 999 para que gráficos cujo a ordenação não for configurada sejam exibidos após os graficos com ordenação configurada.
IMPORTANTE Quando o CODE_TYPE for PHP é necessário que o código esteja tratado (escaped), uma vez que se trata de um bloco JSON. Para tanto, existem ferramentas online, como freeformatter.com. Tomando o exemplo acima, temos o seguinte código para a série categories: {.is-danger}
$user = \core\xDS::getUser();
$empresa = $user->EMPRESA_ATUAL;
$local = $user->LOCAL_ATUAL;
$filial = $user->FILIAL_ATUAL;
$timezone = $this->user->TIMEZONE ?? date_default_timezone_get();
$dIni = (empty($inicio)) ? new DateTime('-2 months', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\/m\/Y', $inicio);
$dFim = (empty($fim)) ? new DateTime('now', new DateTimeZone($timezone)) : DateTime::createFromFormat('d\/m\/Y', $fim);
$comeco = date_format($dIni,'Y-m-d');
$final = date_format($dFim,'Y-m-d');
if (!empty($modelo)) {
$modelos = (is_array($modelo)) ? ' and m.SEQ_DB in (' . implode(',', $modelo) . ') ' : " and m.SEQ_DB = {$modelo} ";
} else {
$modelos = '';
}
$sql = "SELECT
distinct m.DESCRICAO Modelo
FROM app_apontamento_maquina a
INNER JOIN app_equipamento e ON a.EQUIPAMENTO_SEQ_DB = e.SEQ_DB
INNER JOIN app_modelo m ON e.MODELO_SEQ_DB = m.SEQ_DB
WHERE DATE(a.INI_DH) between '{$comeco}' and '{$final}'
and a.empresa = {$empresa} and a.local in ({$local},9999) and a.filial in ({$filial},9999) and a.ativo = 1 and a.deleted = 0
{$modelos} GROUP BY m.SEQ_DB;";
$todosModelos = \core\ConexaoDB::query($sql, $params = []);
$series = [];
foreach ($todosModelos as $model){
array_push($series,$model['Modelo']);
}
return $series;
Gráficos
Vídeos para ajuda: Criando gráficos para dashboard no NFS
Parte 1 de 5
Parte 2 de 5
Parte 3 de 5
Parte 4 de 5
Parte 5 de 5
Configuração de Reload No Dashboard
A configuração abaixo deve ser inserida quando o objetivo é atualizar os dados de todos os gráficos da tela ao mesmo tempo.
Obs: O tempo de reload a ser devinido está em segundos, logo se for a cada 1 minuto o valor deve ser 60 (segundos). O valor deve ser maior ou igual a 60 (1 minuto), caso contrário não será considerado
A configuração deve ser inserida no campo OPTIONS da tabela nfs_generic_dashboard
Exemplo: Reload a cada 1 minutos
{
"reloadTime": 60
}
Configuração de Reload individual por gráfico/relatorio
Aviso! Se for adicionado o reloadTime individual em algum gráfico ou relatório, o reload configurado na tabela nfs_generic_dashboard será ignorado {.is-warning}
Para configurar o reload automático individual em um gráfico, basta adicionar no campo OPTIONS da tabela nfs_generic_chart o item reloadTime, conforme o exemplo abaixo:
Exemplo: Reload a cada 3 minutos
{
"reloadTime": 180
}
Obs: O tempo de reload deve ser inserido em segundos!
Exibir Relatório no Dashboard
Para exibir um relatório na tela de Dashboard deve ser inserido no campo OPTIONS da tabela nfs_generic_chart o nome do relatório, que pode ser consultado na tabela nfs_reports no campo NAME.
No exemplo abaixo temos um relatório com o NAME = planejamento_diario_trato_madeira, logo, deve ser inserido no item report da configuração, como no exemplo abaixo:
{
"report": "planejamento_diario_trato_madeira"
}
Para adicionar o reload automático no relatório basta adicionar à configuração o item reloadTime, como no exemplo a seguir:
{
"report": "planejamento_diario_trato_madeira",
"reloadTime": 180
}
Obs: O tempo de reload deve ser inserido em segundos!
Aviso! Se for adicionado o reloadTime individual em algum gráfico ou relatório, o reload configurado na tabela nfs_generic_dashboard será ignorado {.is-warning}
Gerar imagem PNG de um gráfico
É possível gerar uma imagem PNG de um gráfico configurado na tabela nfs_generic_chart ou passar diretamente uma configuração de um gráfico no modelo Highcharts (modelos: https://www.highcharts.com/demo)
Exemplo:
//['chartConfig'] -> enviando uma configuração highcarts diretamente
$args['chartConfig'] = '{"title": {"text": "Steep Chart"}, "xAxis": {"categories": ["Jan", "Feb", "Mar"]}, "series": [{"data": [29.9, 71.5, 106.4]}]}';
//ou
//['seqDb'] -> pegar uma configuração da tabela nfs_generic_chart
$seqdb = 161; //seqdb da tabela nfs_generic_chart.
$args['seqDb'] = $seqdb;
$imgPng = ImageService::getHighchartsImage($args);
echo '<img src="'.$imgPng.'">';
Inserir a imagem de um grafico em um relatorio
Para inserir a imagem de um gráfico no relatório basta definir como no exemplo acima se o gráfico virá de uma configuração ja feita na tabela nfs_generic_chart (SEQ_DB) ou se será gerada manualmente (ChartConfig).
Passo 01 - Inserir o código no entrypoint e enviar através do inputValues como no exemplo abaixo:
Imagem gerada a partir de uma configuração pronta na tabela nfs_generic_chart:
//['seqDb'] -> pegar uma configuração da tabela nfs_generic_chart
$seqDb = 161; //seqdb da tabela nfs_generic_chart.
$args['seqDb'] = $seqDb;
$imgPng = ImageService::getHighchartsImage($args);
if (empty($img)){
//salva no logs o erro, caso ocorra falha
NFSLogger::error('Falha ao tentar pegar imagem de um grafico da tabela nfs_generic_chart, seqDB = '.$seqDb, 'EntryPoint', $imgPng);
} else {
//envia o base64 gerado para o relatório na variavel chartBase64
$this->queryData['chartBase64'] = $imgPng;
}
ou
Imagem gerada a partir de uma configuração feita manualmente
//['chartConfig'] -> enviando uma configuração highcarts diretamente
$args['chartConfig'] = '{"title": {"text": "Steep Chart"}, "xAxis": {"categories": ["Jan", "Feb", "Mar"]}, "series": [{"data": [29.9, 71.5, 106.4]}]}';
$imgPng = ImageService::getHighchartsImage($args);
if (empty($img)){
//salva no logs o erro, caso ocorra falha
NFSLogger::error('Falha ao tentar pegar imagem de um grafico', 'EntryPoint', 'erro ao obter imagem do gráfico');
} else {
//envia o base64 gerado para o relatório na variavel chartBase64
$this->queryData['chartBase64'] = $imgPng;
}
Gerar imagem de um grafico no MOBILE
Exemplo de configuração do gráfico:
<body>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.7/css/all.css">
<div>
<table>
<tr>
<td>
<figure class="highcharts-figure">
<div id="tmo" class="chart-container"></div>
</figure>
</td>
</table>
</div>
<script>
var gaugeOptions = {
chart: {
type: 'gauge',
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
},
title: null,
pane: {
startAngle: -100,
endAngle: 100,
background: [{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#FFF'],
[1, '#333']
]
},
borderWidth: 0,
outerRadius: '109%'
}, {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#333'],
[1, '#FFF']
]
},
borderWidth: 1,
outerRadius: '107%'
}, {
// default background
}, {
backgroundColor: '#DDD',
borderWidth: 0,
outerRadius: '105%',
innerRadius: '103%'
}]
},
exporting: {
enabled: false
},
tooltip: {
enabled: false
},
// the value axis
yAxis: {
minorTickInterval: 'auto',
minorTickWidth: 1,
minorTickLength: 10,
minorTickPosition: 'inside',
minorTickColor: '#666',
tickPixelInterval: 30,
tickWidth: 2,
tickPosition: 'inside',
tickLength: 10,
tickColor: '#666',
labels: {
step: 2,
rotation: 'auto'
},
},
credits: {
enabled: false
}
};
var columnBasic = Highcharts.chart('tmo', Highcharts.merge(gaugeOptions, {
chart: {
type: 'column'
},
xAxis: {
categories: [
'TMO'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Tempo (segundos)'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: []
}));
function loadData() {
xMovaJsApi.getData('onDataReceived');
}
function onDataReceived(result) {
if (result) {
//xMovaJsApi.toast(result);
result = JSON.parse(result);
if (columnBasic) {
/* //OK - MAS OS REGISTROS PRECISAM EXISTIR EM SERIES PARA SEREM ATUALIZADOS
let tempo_padrao = result[0].value;
let tempo_apontado = result[1].value;
let point = columnBasic.series[0].points[0];
point.update(parseFloat(tempo_padrao));
let point2 = columnBasic.series[1].points[0];
point2.update(parseFloat(tempo_apontado));
*/
/* //OK - MAS NÃO ATUALIZA O NAME
var count = 0;
result.forEach(function(element) {
let data = element.value;
let name = element.desc;
let point = columnBasic.series[count].points[0];
point.update(parseFloat(data));
count ++;
});
*/
//LIMPAR DADOS DA SERIES
var series_ids = [];
for (var s in columnBasic.series) {
series_ids.push(columnBasic.series[s].options.id);
}
for (var id in series_ids) {
columnBasic.get(id).remove(false);
}
//ADICIONAR DADOS NA SERIES
result.forEach(function (item) {
columnBasic.addSeries({
name: item.desc,
data: [parseFloat(item.value)]
}, false);
});
columnBasic.redraw();
}
}
setTimeout(function () {
loadData();
}, 10000);
}
loadData();
</script>
</body>