Frontend coins and charts

This commit is contained in:
2021-07-14 10:12:22 -04:00
parent 4a321b4105
commit 2859574848
5 changed files with 368 additions and 41 deletions

View File

@ -12,4 +12,6 @@ class Coins {
public function get(Request $request, Response $response, View $view, $coin_id): Response { public function get(Request $request, Response $response, View $view, $coin_id): Response {
return $view->render($response, 'coins.show', compact('coin_id')); return $view->render($response, 'coins.show', compact('coin_id'));
} }
public function values(Request $request, Response $response, View $view, $coin_id): Response {
}
} }

View File

@ -37,23 +37,26 @@
api: '{{$urls->api}}', api: '{{$urls->api}}',
base: '{{$urls->base}}' base: '{{$urls->base}}'
}, },
table: null,
modal: null, modal: null,
setup: function(table, modal) { setup: function(table, modal) {
this.table = table
this.modal = modal this.modal = modal
table.find('plus icon').css('cursor', 'pointer').click(() => { table.find('plus icon').css('cursor', 'pointer').click(() => {
addCoin() addCoin()
}) })
table.find('tbody').append($('<div></div>').attr('class', 'ui active dimmer').append(
$('<div></div>').attr('class', 'ui loader')
))
table.find('.plus.icon').css('cursor', 'pointer').click((e) => { table.find('.plus.icon').css('cursor', 'pointer').click((e) => {
this.add() this.add()
}) })
this.load(table) this.load()
}, },
load: function(table) { load: function() {
const url = this.urls.api + '/coins' const url = this.urls.api + '/coins'
const table = this.table
const body = table.find('tbody') const body = table.find('tbody')
table.find('tbody').append($('<div></div>').attr('class', 'ui active dimmer').append(
$('<div></div>').attr('class', 'ui loader')
))
$.getJSON(url, (data) => { $.getJSON(url, (data) => {
body.html('') body.html('')
data.coins.forEach((v) => { data.coins.forEach((v) => {
@ -95,6 +98,12 @@
).append( ).append(
$('<input />').attr('type', 'text').attr('name', 'name') $('<input />').attr('type', 'text').attr('name', 'name')
) )
).append(
$('<div></div>').attr('class', 'field').append(
$('<label></label>').html('Identificador')
).append(
$('<input />').attr('type', 'text').attr('name', 'identifier')
)
).append( ).append(
$('<div></div>').attr('class', 'field').append( $('<div></div>').attr('class', 'field').append(
$('<label></label>').html('Código') $('<label></label>').html('Código')
@ -134,6 +143,7 @@
const fields = [ const fields = [
'name', 'name',
'code', 'code',
'identifier',
'prefix', 'prefix',
'suffix', 'suffix',
'decimals', 'decimals',
@ -149,7 +159,7 @@
data = JSON.stringify(data) data = JSON.stringify(data)
$.post(url, data, (response) => { $.post(url, data, (response) => {
if (response.created === true) { if (response.created === true) {
return reload() return this.load()
} }
}, 'json') }, 'json')
} }
@ -226,7 +236,7 @@
data: data, data: data,
success: (response) => { success: (response) => {
if (response.edited === true) { if (response.edited === true) {
return reload() return this.load()
} }
}, },
dataType: 'json' dataType: 'json'
@ -244,7 +254,7 @@
success: (response) => { success: (response) => {
console.debug(response) console.debug(response)
if (response.deleted === true) { if (response.deleted === true) {
return reload() return this.load()
} }
}, },
dataType: 'json' dataType: 'json'

View File

@ -2,30 +2,131 @@
@section('page_content') @section('page_content')
<h3 class="ui header">Moneda - <span class="coin_name"></span></h3> <h3 class="ui header">Moneda - <span class="coin_name"></span></h3>
<div class="ui list" id="coin_data"> <div class="ui list" id="coin_data"></div>
</div> <canvas id="coin_graph" width="400" height="200"></canvas>
<table class="ui table" id="coin_values">
<thead>
<tr>
<th>
Fecha
</th>
<th>
Valor
</th>
</tr>
</thead>
<tbody></tbody>
</table>
@endsection @endsection
@push('page_scripts') @push('page_scripts')
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(() => { const coin = {
const id = '{{$coin_id}}' id: {{$coin_id}},
const api_url = '{{$urls->api}}' urls: {
const url = api_url + '/coin/' + id api: '{{$urls->api}}'
$.getJSON(url, (data) => { },
$('.coin_name').html(data.coin.name) data: {},
values: {},
draw: function() {
$('.coin_name').html(this.data.name)
$('#coin_data').append( $('#coin_data').append(
$('<div></div>').attr('class', 'item').html('Código: ' + data.coin.code) $('<div></div>').attr('class', 'item').html('Código: ' + this.data.code)
).append( ).append(
$('<div></div>').attr('class', 'item').html('Prefijo: ' + data.coin.prefix) $('<div></div>').attr('class', 'item').html('Prefijo: ' + this.data.prefix)
).append( ).append(
$('<div></div>').attr('class', 'item').html('Sufijo: ' + data.coin.suffix) $('<div></div>').attr('class', 'item').html('Sufijo: ' + this.data.suffix)
).append( ).append(
$('<div></div>').attr('class', 'item').html('Decimales: ' + data.coin.decimals) $('<div></div>').attr('class', 'item').html('Decimales: ' + this.data.decimals)
).append( ).append(
$('<div></div>').attr('class', 'item').html('Url: ' + data.coin.ref_url) $('<div></div>').attr('class', 'item').html('Url: ' + this.data.ref_url)
) )
}) },
loading: function(elem) {
elem.html('')
elem.append(
$('<div></div>').attr('class', 'ui active dimmer').append(
$('<div></div>').attr('class', 'ui indeterminate elastic text loader').html('Cargando los datos.')
)
)
},
getData: function() {
const elem_id = '#coin_data'
this.loading($(elem_id))
const url = this.urls.api + '/coin/' + this.id
$.getJSON(url, (data) => {
$(elem_id).html('')
this.data = data.coin
this.draw()
this.getValues()
})
},
getValues: function() {
/*const elem_id = '#coin_values'
$(elem_id).show()
this.loading($(elem_id).find('tbody'))*/
this.loading($('#coin_graph'))
const url = this.urls.api + '/coin/' + this.id + '/values'
$.getJSON(url, (data) => {
//$(elem_id).find('tbody').html('')
this.values = data.values
this.graphValues()
})
},
showValues: function() {
const list_id = '#coin_values'
list = $(list_id).find('tbody')
const f = Intl.DateTimeFormat('es-CL', {dateStyle: 'medium', timeStyle: 'long'})
$.each(this.values, (i, elem) => {
const d = new Date(elem.date_time)
list.append(
$('<tr></tr>').append(
$('<td></td>').html(f.format(d))
).append(
$('<td></td>').html(elem.formatted)
)
)
})
},
graphValues: function() {
const ctx = document.getElementById('coin_graph').getContext('2d')
let labels = []
let values = []
const f = Intl.DateTimeFormat('es-CL', {dateStyle: 'medium'})
$.each(this.values, (i, el) => {
const d = new Date(el.date_time)
labels.push(f.format(d))
values.push(el.value)
})
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: this.data.name,
data: values,
fill: false,
borderWidth: 1,
tension: 0.1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
})
},
setup: function() {
this.getData()
$('#coin_values').hide()
}
}
$(document).ready(() => {
coin.setup()
}) })
</script> </script>
@endpush @endpush

View File

@ -1,5 +1,220 @@
@extends('layout.base') @extends('layout.base')
@section('page_content') @section('page_content')
Home <h3>
Home
</h3>
<div class="ui top attached tabular menu" id="coins_menu">
</div>
@endsection @endsection
@push('page_scripts')
<script type="text/javascript">
const types = ['month', 'months', 'year']
const coins_menu = $('#coins_menu')
const f = Intl.DateTimeFormat()
let active = false
class Coin {
constructor(data) {
this.data = data
this.values = {
month: [],
months: [],
year: []
}
}
getValues(api_url) {
const base_url = api_url + '/coin/' + this.data.id + '/values/'
let promises = []
$.each(types, (i, t) => {
let url = base_url + t
promises.push($.getJSON(url, (data) => {
this.values[t] = data.values
}))
})
Promise.all(promises).then(() => {
this.draw()
})
}
size() {
let sum = 0
$.each(types, (i, t) => {
sum += this.values[t].length
})
return sum
}
draw() {
if (this.size() == 0) {
return
}
const m = $('<div></div>').attr('class', 'item').attr('data-tab', this.data.code).html(this.data.name)
coins_menu.append(m)
const tabs = $('<div></div>').attr('class', 'ui top attached tabular menu')
const column = $('<div></div>').attr('class', 'eight wide column').append(tabs)
let active2 = false
$.each(types, (i, t) => {
if (this.values[t].length == 0) {
return
}
const canvas = $('<canvas></canvas>').attr('id', 'canvas_' + t + '_' + this.data.code).attr('width', '200').attr('height', '200')
const tab = $('<div></div>').attr('class', 'item').attr('data-tab', this.data.code + t).html(t.toLowerCase().split(' ').map(function(word) {
return (word.charAt(0)).toUpperCase() + word.slice(1)
}).join(' '))
tabs.append(tab)
const sg = $('<div></div>').attr('class', 'ui bottom attached tab segment').attr('data-tab', this.data.code + t).append(
$('<div></div>').attr('class', 'content').append(canvas)
)
column.append(sg)
if (!active2) {
tab.addClass('active')
sg.addClass('active')
active2 = true
}
let labels = []
let values = []
$.each(this.values[t], (k, val) => {
const d = new Date(val.date_time)
labels.push(f.format(d))
values.push(val.value)
})
const min = Math.min(...values)
const max = Math.max(...values)
const range = max - min
const chart = new Chart(canvas[0], {
type: 'line',
data: {
labels: labels,
datasets: [{
label: this.data.name,
data: values,
fill: false,
borderWidth: 1,
tension: 0.1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
min: min - range / 2,
max: max + range / 2
}/*,
x: {
display: false
}*/
}
}
})
})
const seg = $('<div></div>').attr('class', 'ui bottom attached tab segment').attr('data-tab', this.data.code).append(
$('<div></div>').attr('class', 'ui centered grid').append(column)
)
coins_menu.after(seg)
if (!active) {
m.addClass('active')
seg.addClass('active')
active = true
}
m.tab()
tabs.find('.item').tab()
}
}
const coins = {
data: [],
urls: {
api: '{{$urls->api}}'
},
getCoins: function() {
const url = this.urls.api + '/coins'
$.getJSON(url, (data) => {
$.each(data.coins, (i, el) => {
const c = new Coin(el)
c.getValues(this.urls.api)
})
})
},
getValues: function() {
let p = []
$.each(this.data, (i, el) => {
const url = this.urls.api + '/coin/' + el.id + '/values/months'
p.push($.getJSON(url, (data) => {
this.data[i].values = data.values
}))
})
Promise.all(p).then(() => {
this.draw()
})
},
draw: function() {
const menu = $('#coin_menu')
const f = Intl.DateTimeFormat()
let active = false
$.each(this.data, (i, el) => {
if (el.values.length == 0) {
return
}
const m = $('<div></div>').attr('class', 'item').attr('data-tab', el.code).html(el.name)
menu.append(m)
const canvas = $('<canvas></canvas>').attr('id', 'canvas' + el.code).attr('width', '200').attr('height', '200')
const seg = $('<div></div>').attr('class', 'ui bottom attached tab segment').attr('data-tab', el.code).append(
$('<div></div>').attr('class', 'ui centered grid').append(
$('<div></div>').attr('class', 'eight wide column').append(canvas)
)
)
menu.after(seg)
if (!active) {
m.addClass('active')
seg.addClass('active')
active = true
}
m.tab()
let labels = []
let values = []
$.each(el.values, (k, val) => {
const d = new Date(val.date_time)
labels.push(f.format(d))
values.push(val.value)
})
const min = Math.min(...values)
const max = Math.max(...values)
const range = max - min
const chart = new Chart(canvas[0], {
type: 'line',
data: {
labels: labels,
datasets: [{
label: el.name,
data: values,
fill: false,
borderWidth: 1,
tension: 0.1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
min: min - range / 2,
max: max + range / 2
}/*,
x: {
display: false
}*/
}
}
})
})
},
setup: function() {
this.getCoins()
}
}
$(document).ready(() => {
coins.setup()
})
</script>
@endpush

View File

@ -33,34 +33,33 @@ return [
}, },
'scripts' => function() { 'scripts' => function() {
$arr = [ $arr = [
[ '<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>',
'full' => '<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>' '<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/semantic.min.js" integrity="sha512-1Nyd5H4Aad+OyvVfUOkO/jWPCrEvYIsQENdnVXt1+Jjc4NoJw28nyRdrpOCyFH4uvR3JmH/5WmfX1MJk2ZlhgQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>',
], '<script src="https://cdn.jsdelivr.net/npm/chart.js@3.4.1/dist/chart.min.js"></script>'
[
'full' => '<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/semantic.min.js" integrity="sha512-1Nyd5H4Aad+OyvVfUOkO/jWPCrEvYIsQENdnVXt1+Jjc4NoJw28nyRdrpOCyFH4uvR3JmH/5WmfX1MJk2ZlhgQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
]
]; ];
foreach ($arr as $i => $a) { foreach ($arr as $i => $a) {
if (strpos($a, '<script') !== false) {
$a = ['full' => $a];
} else {
$a = ['url' => $a];
}
$arr[$i] = (object) $a; $arr[$i] = (object) $a;
} }
return $arr; return $arr;
}, },
'styles' => function() { 'styles' => function() {
$arr = [ $arr = [
[ '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/semantic.min.css" integrity="sha512-g/MzOGVPy3OQ4ej1U+qe4D/xhLwUn5l5xL0Fa7gdC258ZWVJQGwsbIR47SWMpRxSPjD0tfu/xkilTy+Lhrl3xg==" crossorigin="anonymous" referrerpolicy="no-referrer" />',
'link' => '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/semantic.min.css" integrity="sha512-g/MzOGVPy3OQ4ej1U+qe4D/xhLwUn5l5xL0Fa7gdC258ZWVJQGwsbIR47SWMpRxSPjD0tfu/xkilTy+Lhrl3xg==" crossorigin="anonymous" referrerpolicy="no-referrer" />' 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/brand-icons.woff2',
], 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/icons.woff2',
[ 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/outline-icons.woff2'
'url' => 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/brand-icons.woff2'
],
[
'url' => 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/icons.woff2'
],
[
'url' => 'https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.7/themes/default/assets/fonts/outline-icons.woff2'
]
]; ];
foreach ($arr as $i => $a) { foreach ($arr as $i => $a) {
if (strpos($a, '<link') !== false) {
$a = ['link' => $a];
} else {
$a = ['url' => $a];
}
$arr[$i] = (object) $a; $arr[$i] = (object) $a;
} }
return $arr; return $arr;