2015-05-07 13 views
14

Sto usando jquery flot charts per rappresentare i miei dati. Ecco l'esempio JSFiddle creato che mostra come dovrebbero apparire i JSON richiesti per il grafico.Creare JSON dinamico da foreach

La fonte è da una procedura immagazzinata MySql che ha l'esempio seguente output:

enter image description here

devo rappresentare nel grafico, i valori count impilati per diverse s innumber' sull'asse y , i valori name sull'asse xe in un altro grafico i valori per outnumber. (in barre impilate).

-Le serie di dati devono corrispondere, pertanto le etichette specifiche devono essere visualizzate nei confronti dei clienti.

Ecco il PHP che ho finora:

$query = $this->db->query("call GetAllCustomersV2($id, $year, $month, $day)"); 
$customers = $query->result_array(); 

foreach ($customers as $customer) { 

    if($customer['innumber'] != null){ 

     $chartInbound['name'] = $customer['name']; 
     $chartInbound['label'] = $customer['innumber']; 
     $chartInbound['count'] = $customer['count']; 
     $chartInbound['customerid'] = $customer['id']; 

     array_push($out['chartInbound'], $chartInbound); 
    } 

    if($customer['outnumber'] != null){ 

     $chartOutbound['name'] = $customer['name']; 
     $chartOutbound['label'] = $customer['outnumber']; 
     $chartOutbound['count'] = $customer['count']; 
     $chartOutbound['customerid'] = $customer['id']; 

     array_push($out['chartOutbound'], $chartOutbound); 
    } 
} 

L'uscita del print_r($out['chartInbound']); è:

Array 
(
[0] => Array 
    (
     [name] => 1st Online Solutions 
     [label] => 01-02 
     [count] => 577 
     [customerid] => 129 
    ) 

[1] => Array 
    (
     [name] => Bookngo 
     [label] => 01-02 
     [count] => 2 
     [customerid] => 95 
    ) 

[2] => Array 
    (
     [name] => Boutixury 
     [label] => 07 
     [count] => 1 
     [customerid] => 14 
    ) 

[3] => Array 
    (
     [name] => Cruise Village 
     [label] => 01-02 
     [count] => 16 
     [customerid] => 25 
    ) 

[4] => Array 
    (
     [name] => Cruise Village 
     [label] => 00 
     [count] => 1 
     [customerid] => 25 
    ) 

[5] => Array 
    (
     [customer] => Cruise Village 
     [label] => 07 
     [countInbound] => 16 
     [minsInbound] => 125 
     [customerid] => 25 
    ) 
    ................... 
) 

L'uscita del print_r(json_encode($out['chartInbound'])); è:

[ 
{ 
    "name": "1st Online Soultions" 
    "label": "01-02", 
    "count": "577", 
    "customerid": "129" 
}, 
{ 
    "name": "Bookngo" 
    "label": "01-020", 
    "count": "2", 
    "customerid": "129" 
}, 
{ 
    "name": "Boutixury" 
    "label": "07", 
    "count": "1", 
    "customerid": "14" 
}, 
{ 
    "name": "Cruise Village" 
    "label": "07", 
    "count": "16", 
    "customerid": "25" 
}, 
................. 
] 

ma questo non è molto utile.

Q: Come posso creare i JSON dinamici mostrati nel jsfiddle precedente, dai dati della query?

+0

I dati nella tua domanda (i dati di MySql) e i dati nel tuo jsfiddle corrispondono ?? – Jeff

+0

il formato di 'chartData' e' chartTicks' dovrebbe essere lo stesso e i loro valori dovrebbero essere popolati dinamicamente – alex

+0

Puoi modificare il processo memorizzato, o è corretto? È possibile attaccare i dati direttamente, tramite una frase SQL? In tal caso, potresti fornire la struttura dei dati, forse potresti semplicemente modificare il modo in cui recuperi i dati per ottenere i dati come se fossero JSON. – Chococroc

risposta

10

Passando attraverso i dati con un ciclo e costruire i newData e newTicks array per flot da usare:

var newData = []; 
var newLabels = []; // only used to get index since newData has objects in it 
var newTicks = []; 

for (var i = 0; i < dataFromServer.length; i++) { 
    var datapoint = dataFromServer[i]; 

    var tick = newTicks.indexOf(datapoint.name); 
    if (tick == -1) { 
     tick = newTicks.length; 
     newTicks.push(datapoint.name); 
    } 

    var index = newLabels.indexOf(datapoint.label); 
    if (index == -1) { 
     index = newLabels.length; 
     newLabels.push(datapoint.label); 

     newDataPoint = { 
      label: datapoint.label, 
      data: [] 
     }; 
     newDataPoint.data[tick] = [tick, datapoint.count]; 
     newData.push(newDataPoint); 
    } else { 
     newData[index].data[tick] = [tick, datapoint.count]; 
    } 
} 
for (var i = 0; i < newTicks.length; i++) { 
    newTicks[i] = [i, newTicks[i]]; 
} 
newLabels = null; 

Ho avuto anche per cambiare la generazione del tooltip in quanto il codice funzionava solo quando tutti i dataseries erano completi e ordinati. Adesso è anche più semplice.

complete fiddle

+0

grazie , ci provi e torni tra un'ora o più – alex

+0

@alex qualche problema? Funziona? – Raidri

+0

puoi fare un piccolo aggiornamento al seguente JsFiddle per ottenere il customerid anche sull'evento click del grafico (evento clic barra). Ho aggiunto la funzione di bind di click plot a jsFiddle: http://jsfiddle.net/t1jgvyLx/ – alex

2

Dovrai trasformare le strutture da solo. Puoi fare questo lato server o lato client. In entrambi i casi, esegui i risultati e crea la struttura che desideri. Attenzione a provare a codificare gli array associativi php in json e fare attenzione al comportamento di NUMERIC_CHECK.

+0

non molto utile ... – alex

+0

Mi dispiace che tu abbia pensato. Non so se ti aspettavi il codice. –

4

Puoi farlo sul lato client (anche se idealmente dovrebbe essere fatto sul lato server), utilizzando qualcosa di simile a:

var table = [ 
    {name: 'a', label: 'l1', count: '15', customerid: '1'}, 
    {name: 'a', label: 'l2', count: '1', customerid: '1'}, 
    {name: 'a', label: 'l3', count: '7', customerid: '1'}, 
    {name: 'b', label: 'l1', count: '3', customerid: '2'}, 
    {name: 'b', label: 'l2', count: '9', customerid: '2'}, 
    {name: 'b', label: 'l3', count: '2', customerid: '2'}, 
    {name: 'c', label: 'l1', count: '1', customerid: '3'}, 
    {name: 'c', label: 'l2', count: '7', customerid: '3'}, 
    {name: 'a', label: 'l3', count: '5', customerid: '4'}, 
    {name: 'a', label: 'l2', count: '6', customerid: '4'} 
]; 

var customers = {}; 
var labels = {}; 

var i; 
for (i = 0; i < table.length; ++i) { 
    customers[table[i].customerid] = table[i].name; 
    labels[table[i].label] = labels[table[i].label] || []; 
    labels[table[i].label].push([+table[i].customerid, +table[i].count]); 
} 

var chartData = []; 
var chartTicks = []; 

for (customer in customers) { 
    if (customers.hasOwnProperty(customer)) { 
     chartTicks.push([+customer, customers[customer]]); 
    } 
} 
for (label in labels) { 
    if (labels.hasOwnProperty(label)) { 
     chartData.push({label: label, data: labels[label]}); 
    } 
} 

Essa rappresenta per i diversi clienti (diversi CustomerIDs) con lo stesso nome (anche se lo Flot non funzionerà molto bene) e i clienti con dati mancanti per alcune etichette. Non dovrebbe essere troppo difficile spostare questa logica in PHP e farlo sul lato server.

EDIT: Ok, non avevo notato che si comporta in modo strano quando ci sono "lacune" labelID. Ecco il codice rivisto: ID

var table = [ 
    {name: 'a', label: 'l1', count: '15', customerid: '1'}, 
    {name: 'a', label: 'l2', count: '1', customerid: '1'}, 
    {name: 'a', label: 'l3', count: '7', customerid: '1'}, 
    {name: 'b', label: 'l1', count: '3', customerid: '2'}, 
    {name: 'b', label: 'l2', count: '9', customerid: '2'}, 
    {name: 'b', label: 'l3', count: '2', customerid: '2'}, 
    {name: 'c', label: 'l1', count: '1', customerid: '3'}, 
    {name: 'c', label: 'l2', count: '7', customerid: '3'}, 
    {name: 'a', label: 'l3', count: '5', customerid: '7'}, 
    {name: 'a', label: 'l2', count: '6', customerid: '7'} 
]; 

var customers = {}; 
var labels = {}; 

var chartData = []; 
var chartTicks = []; 

var i; 
var customerNo = 0; 
for (i = 0; i < table.length; ++i) { 
    if(!customers.hasOwnProperty(table[i].customerid)) { 
     customers[table[i].customerid] = table[i].name; 
     chartTicks.push([customerNo, table[i].name]); 
     customerNo++; 
    } 
    labels[table[i].label] = labels[table[i].label] || []; 
    labels[table[i].label].push([customerNo - 1, +table[i].count]); 
} 

for (label in labels) { 
    if (labels.hasOwnProperty(label)) { 
     chartData.push({label: label, data: labels[label]}); 
    } 
} 

Label sono dati nell'ordine in cui appaiono nella tabella che proviene dal server. (Anche se distingue ancora tra i due clienti con lo stesso nome ma diversi CustomerIDs)

+0

grazie, ma il problema con quanto sopra è che flot si aspetta una serie di dati sia per chartTicks sia per i dati sotto forma di "dati": [[0,577], [1,2], [2,16], [3, 11], [4,22], [5,43]], .... Invece di cusomeride dovrebbe essere l'indice (posizione del cliente nel grafico) e dovrebbe corrispondere alle etichette con i clienti, come nel jsfiddle - – alex

4

Solo un'idea, suppongo che si sta utilizzando un gruppo di stored procedure. Se fosse possibile modificarlo e aggiungere un WITH ROLLUP il database avrebbe calcolato il conteggio per voi ... Vedere https://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html o cercare SO per suggerimento

+1

grazie , ecco alcune informazioni utili, l'ho aggiunto alla stored procedure! – alex

2

Sembra che i vostri punti di dati in chartTicks[i] debbano corrispondere all'ordine dei tick in chartData[i].data. Un modo per garantire tale corrispondenza è ordinare i dati in base al nome in sql e impilare i risultati per cliente prima e etichettare secondariamente in php.

$query = $this->db->query("call GetAllCustomersV2($id, $year, $month, $day)"); 
$customers = $query->result_array(); //should be sorted by name 
$results = array(); 

foreach ($customers as $customer) { 
    $i = is_array($results[$customer['name']][$customer['innumber']]) 
     ? count($results[$customer['name']][$customer['innumber']]) 
     : 0; 

    //stack data points by customer name first and label second 
    $results[$customer['name']][$customer['innumber']][] = array($i,$customer['count']); 
} 

$chartData = array(); 
$chartTicks = array(); 
$i=0; 

foreach($results as $name => $labels) { 
    $chartTicks[] = array($i++,$name); 
    foreach($labels as $label => $data) { 
     $chartData[] = array(
      'label' => $label, 
      'data' => $data, 
     ); 
    } 
} 

print json_encode($chartData); 
print json_encode($chartTicks); 
2

Questo è un modo conciso per trasformare la struttura dati corrente JSON in uscita desiderata:

var reduced; 
var chartData = Object.keys(reduced = data.reduce(function(a, b) { 
    if(a[b.label]) { 
    a[b.label].push([a[b.label].length, parseInt(b.count, 10)]); 
    } else { 
    a[b.label] = [[0, parseInt(b.count, 10)]]; 
    } 
    return a; 
}, {})).map(function(key) { 
    return { 
    label: key, 
    data: reduced[key] 
    }; 
}); 

Fiddle: http://jsfiddle.net/rdkgbteq/1/

qui è la stessa cosa in PHP, se si vogliono trasformare i dati sul server:

$reduced = array_reduce($data, function($result, $current) { 
    if(array_key_exists($current['label'], $result)) { 
     array_push($result, [count($result[$current['label']]), $current['count']]); 
    } else { 
     $result[$current['label']] = [[0, $current['count']]]; 
    } 
    return $result; 
}, array()); 

$formatted = array_map(function($key) { 
    return array(
     'label' => $key, 
     'data' => $reduced[$key] 
    ); 
}, array_keys($reduced)); 

echo json_encode($formatted); 

Fatemi sapere se volete m e per approfondire cosa sta succedendo qui.