In my vuejs laravel application I'm trying to implement a bar chart using apexcharts module.
<apexchart ref="apexChart" :options="chartOptions" :series="chartData" type="bar"></apexchart>
Following is my <sctipt></script>
<script>
import ApexCharts from 'apexcharts'
import axios from 'axios'
export default {
data() {
return {
daywise_sales: [],
chartData: [],
mostSellingDay: '',
leastSellingDay: '',
chartOptions: {
xaxis: {
categories: []
},
yaxis: {
title: {
text: "Sales"
}
},
chart: {
id: 'daywise_sales'
},
title: {
text: 'Day wise sales'
}
}
}
},
mounted() {
axios.get('/shopify-day-wise-sales')
.then(response => {
this.daywise_sales = response.data.day_totals;
this.chartOptions.xaxis.categories = Object.keys(this.daywise_sales)
.map(date => {
return new Date(date).toLocaleString('default', {weekday: 'long'});
});
// Ensure that the chartData property is correctly set with the data
this.chartData = [{data: Object.values(this.daywise_sales)}];
// Find the most and least selling days
let mostSellingDay = '';
let mostSellingDaySales = 0;
let leastSellingDay = '';
let leastSellingDaySales = Number.MAX_SAFE_INTEGER;
for (let date in this.daywise_sales) {
if (this.daywise_sales[date] > mostSellingDaySales) {
mostSellingDay = date;
mostSellingDaySales = this.daywise_sales[date];
}
if (this.daywise_sales[date] < leastSellingDaySales) {
leastSellingDay = date;
leastSellingDaySales = this.daywise_sales[date];
}
}
this.mostSellingDay = new Date(mostSellingDay).toLocaleString('default', {weekday: 'long'});
this.leastSellingDay = new Date(leastSellingDay).toLocaleString('default', {weekday: 'long'});
})
.catch(error => {
console.log(error);
});
}
}
</script>
From my back end for the response.data.day_totals i get following array
array:8 [
"2023-01-11" => 1
"2023-01-09" => 1
"2023-01-05" => 0
"2023-01-06" => 0
"2023-01-07" => 0
"2023-01-08" => 0
"2023-01-10" => 0
"2023-01-12" => 0
]
Issue is I need to set the dates in short names (Sat, Sun, Mon, Tue...etc) instead of 1,2... for the xaxis and for the yaxis the number of sales per each day...
This is my current chart.
How can I fix my x-axis?
I think you need this part of doc https://apexcharts.com/docs/formatting-axes-labels/
Related
In my Vue app I am using Apexcharts to display some data.
I am grabbing the data from my Firestore database by using a realtime listener.
The chart is working as it should and I am also getting the data in realtime. The problem is that my chart is not updating itself with the new data, and I am not sure on how to approach it.
I am fetching the data my parent component through this script:
onMounted(async () => {
const unsub = onSnapshot(doc(db, "testUsers", "rtBp8UHReBE2rACDBHij"), (doc) => {
getWeight.value = doc.data();
});
watchEffect((onInvalidate) => {
onInvalidate(() => unsub());
});
});
I am sending the data to my child component through props like this:
watch(
() => props.getWeight,
(getWeights) => {
weight.value = [...getWeights.weightData.weight];
let numeric = { day: "numeric", month: "numeric" };
getWeights.weightData.date.forEach((dates) => {
date.value.push([dates.toDate().toLocaleDateString("se-SW", numeric)]);
}),
}
);
My chart in the child component looks something like this:
<apexchart class="apexchart" type="line" :options="options" :series="series">
</apexchart>
<script>
export default {
props: ["weight", "date"],
setup(props) {
return {
options: {
xaxis: {
type: "category",
categories: props.date,
axisBorder: {
show: false,
},
},
},
series: [
{
name: "Værdi",
data: props.weight,
},
],
};
},
};
</script>
How can I make my chart update with the new data from the realtime listener?
If in chart options you add id you would be able to call exec and update your chart
Example:
import ApexCharts from "apexcharts";
ApexCharts.exec('chartId', 'updateOptions', {
series: [
{
name: 'Værdi',
data: newWeights,
},
],
xaxis: {
categories: newDates,
},
})
Please Help! How to add "myCss" class for one date before bookedDates? (17 Aug and 17 Sep in my example). The idea is to paint a different color day before booked.
This is example code for which I am trying to do this:
const DateTime = easepick.DateTime;
const bookedDates = [
'18-08-2022', '19-08-2022', '20-08-2022', '18-09-2022', '19-09-2022', '20-09-2022',
].map(d => {
if (d instanceof Array) {
const start = new DateTime(d[0], 'DD-MM-YYYY');
const end = new DateTime(d[1], 'DD-MM-YYYY');
return [start, end];
}
return new DateTime(d, 'DD-MM-YYYY');
});
const picker = new easepick.create({
element: document.getElementById('datepicker'),
css: [
'https://cdn.jsdelivr.net/npm/#easepick/bundle#1.2.0/dist/index.css',
'https://easepick.com/css/demo_hotelcal.css',
],
readonly: true,
zIndex: 10,
format: "DD MMM YYYY",
readonly: false,
plugins: ['RangePlugin', 'LockPlugin'],
RangePlugin: {
tooltipNumber(num) {
return num - 1;
},
locale: {
one: 'night',
other: 'nights',
},
},
LockPlugin: {
minDate: new Date(),
minDays: 2,
inseparable: true,
filter(date, picked) {
if (picked.length === 1) {
const incl = date.isBefore(picked[0]) ? '[)' : '(]';
return !picked[0].isSame(date, 'day') && date.inArray(bookedDates, incl);
}
return date.inArray(bookedDates, '[)');
},
}
});
<script src="https://cdn.jsdelivr.net/npm/#easepick/bundle#1.2.0/dist/index.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#easepick/bundle#1.2.0/dist/index.umd.min.js"></script>
<input readonly="readonly" id="datepicker"/>
You need to use a setup option in easepick.create({ ... }):
Before date
setup(picker) {
picker.on('view', (event) => {
const { view, target, date } = event.detail;
if (view === 'CalendarDay') {
const dayAfter = date.clone().add(1, 'day');
if (
! picker.options.LockPlugin.filter(date, picker.datePicked)
&& picker.options.LockPlugin.filter(dayAfter, picker.datePicked)
) {
target.classList.add('myCss');
}
}
});
},
After date
setup(picker) {
picker.on('view', (event) => {
const { view, target, date } = event.detail;
if (view === 'CalendarDay') {
const dayBefore = date.clone().subtract(1, 'day');
if (
picker.options.LockPlugin.filter(dayBefore, picker.datePicked)
&& ! picker.options.LockPlugin.filter(date, picker.datePicked)
) {
target.classList.add('myCss');
}
}
});
}
I'm using Vue js to display and edit details of a person. The person being edited has a list of favourite colours that I want to display as a list of checkboxes. When I change the colours selected, and click the 'Update' button, the person object should be updated accordingly, so I can pass back to the api to update.
I've got as far as displaying the Person object's colours correctly against their respective checkboxes. But I'm struggling with passing the changes to the colour selection, back to the Person object. Below is my checkbox list and details of how I've tried to implement this. Is there a better way of doing this?
I've tried using 'b-form-checkbox-group'. Below is my code.
Please note - The list of available colours is dynamic, but I've temporarily hardcoded a list of colours ('colourData') till I get this working.
Also, in the 'UpdatePerson' method, I've commented out my attempts to get the selected colours mapped back to the Person object.
<template>
<form #submit.prevent="updatePerson">
<b-form-group label="Favourite colours:">
<b-form-checkbox-group id="favColours"
v-model="colourSelection"
:options="colourOptions"
value-field="item"
text-field="name">
</b-form-checkbox-group>
</b-form-group>
<div class="container-fluid">
<b-btn type="submit" variant="success">Save Record</b-btn>
</div>
</form>
</template>
<script>
import service from '#/api-services/colours.service'
export default {
name: 'EditPersonData',
data() {
return {
personData: {
personId: '',
firstName: '',
lastName: '',
colours:[]
},
colourData: [
{ colourId: '1', isEnabled: '1', name: 'Red' },
{ colourId: '2', isEnabled: '1', name: 'Green' },
{ colourId: '3', isEnabled: '1', name: 'Blue' },
],
selectedColours: [],
colourSelection: []
};
},
computed: {
colourOptions: function () {
return this.colourData.map(v => {
let options = {};
options.item = v.name;
options.name = v.name;
return options;
})
}
},
created() {
service.getById(this.$route.params.id).then((response) => {
this.personData = response.data;
this.colourSelection = response.data.colours.map(function (v) { return v.name; });
this.selectedColours = response.data.colours;
}).catch((error) => {
console.log(error.response.data);
});
},
methods: {
async updatePerson() {
//const cs = this.colourSelection;
//const cd = this.colourData.filter(function (elem) {
// if (cs.indexOf(elem.name) != -1) { return elem;}
//});
//this.personData.colours = [];
//this.personData.colours = cd;
service.update(this.$route.params.id, this.personData).then(() => {
this.personData = {};
}).catch((error) => {
console.log(error.response.data);
});
},
}
}
</script>
Any help wold be much appreciated.
Thanks
I got this working by making the below changes to the commented part in the 'updatePerson()' method:
methods: {
async updatePerson() {
const cs = this.colourSelection;
const cd = this.colourData.filter(function (elem) {
if (cs.some(item => item === elem.name)) { return elem; }
});
this.personData.colours = [];
this.personData.colours = cd;
service.update(this.$route.params.id, this.personData).then(() => {
this.personData = {};
}).catch((error) => {
console.log(error.response.data);
});
}
}
I am using an expanding table component to display a list of attendants that have worked at a particular store. I need to do two things:
1) I need to insert a new row under the last attendant that sums the total column for each attendant see attached screenshot).
2) I need to calculate the running total which would be something like current + previous I imagine.
Here's what I have so far:
store-totals.list.view.html
<div class="page-section-header">
<h1 class="list-title">Store Tender Totals</h1>
</div>
<act-search-box
default-type="attendant"
search="vm.search"
type="vm.type"
placeholder="Enter a Store ID"
type-options="[
{ label: 'Terminal', value : 'terminal' },
{ label: 'Total', value: 'total' },
{ label: 'Attendant', value: 'attendant' }
]"
on-search="vm.getAttendants()">
</act-search-box>
<div class="page-section-below-search-box single-width" style="width:27%;">
<span style="float:left;margin-top:2.2%;font-size:14px;">Showing totals for</span>
<act-date-picker model="vm.date" placeholder="Select a date" on-change="vm.getAttendants()">
</act-date-picker>
</div>
<act-expanding-table
list="vm.attendantNames"
ng-hide="vm.emptyResult"
properties="[
{ type: 'attendantName', size: 2, label: 'Attendant Name'},
{ type: 'total', size: 2, label: 'Total', format:'currency'},
{ type: 'runningTotal', size:2, label: 'Running Total', format:'currency'}
]"
allow-selecting="true">
<div>
<div class="col-xs-12 form-section-header">
<h4>Tender Totals</h4>
</act-expanding-table>
<act-error-message ng-show="vm.errorMessage">{{ vm.errorMessage }}</act-error-message>
store-totals-list.controller.js
import { digest, showLoader } from 'act/services/events';
import 'act/components';
import Searcher from 'act/services/lists/searcher';
import * as moment from 'moment';
import * as api from '../services/totals';
import {header, dev} from 'act/services/logger';
import {goToError} from 'act/services/controller-helpers';
import '../components/store-total';
const defaultStartDate = moment().startOf('day');
export default class StoreTotalsController {
constructor() {
this.attendantNames = [];
this.stores = [];
this.emptyResult = true;
this.totals = 0;
}
getAttendants() {
showLoader('Searching');
const baseUrl = '/src/areas/store-totals/services/tender-total-data.json';
const getStores = new Request(baseUrl, {
method: 'GET'
});
fetch(getStores).then(function(response){
return response.json();
}).then(resp => {
if (!(resp[0] && resp[0].error)) {
this.attendantNames = resp.stores[0].attendants;
this.attendantNames.forEach(a=>{
this.totals += a.total;
console.log(this.totals);
})
this.emptyResult = false;
this.errorMessage = null;
} else {
this.errorMessage = resp[0].error.name;
}
digest();
showLoader(false);
});
}
searchIfReady() {
if (this.search && this.date && this.date.isValid()) {
this.getSearch();
}
}
updateDate(date) {
this.date = moment(date).startOf('day');
this.searchIfReady();
}
}
StoreTotalsController.$inject = ['$stateParams'];
I am trying to use React Data Grid in my project and I want to use row drag and drop and Drag Columns to Reorder features together.
I tried to do this by passing draggable: true for ReactDataGrid column property and wrapping the ReactDataGrid and Draggable.Container with DraggableHeader.DraggableContainer.
It makes column header moveable but it does not trigger onHeaderDrop action in DraggableContainer and it gave a console error Uncaught TypeError: Cannot read property 'id' of undefined.
I change example23-row-reordering.js according to the description above.
const ReactDataGrid = require('react-data-grid');
const exampleWrapper = require('../components/exampleWrapper');
const React = require('react');
const {
Draggable: { Container, RowActionsCell, DropTargetRowContainer },
Data: { Selectors },
DraggableHeader: {DraggableContainer}
} = require('react-data-grid-addons');
import PropTypes from 'prop-types';
const RowRenderer = DropTargetRowContainer(ReactDataGrid.Row);
class Example extends React.Component {
static propTypes = {
rowKey: PropTypes.string.isRequired
};
static defaultProps = { rowKey: 'id' };
constructor(props, context) {
super(props, context);
this._columns = [
{
key: 'id',
name: 'ID',
draggable: true
},
{
key: 'task',
name: 'Title',
draggable: true
},
{
key: 'priority',
name: 'Priority',
draggable: true
},
{
key: 'issueType',
name: 'Issue Type',
draggable: true
}
];
this.state = { rows: this.createRows(1000), selectedIds: [1, 2] };
}
getRandomDate = (start, end) => {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
};
createRows = (numberOfRows) => {
let rows = [];
for (let i = 1; i < numberOfRows; i++) {
rows.push({
id: i,
task: 'Task ' + i,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.floor((Math.random() * 3) + 1)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.floor((Math.random() * 3) + 1)],
startDate: this.getRandomDate(new Date(2015, 3, 1), new Date()),
completeDate: this.getRandomDate(new Date(), new Date(2016, 0, 1))
});
}
return rows;
};
rowGetter = (i) => {
return this.state.rows[i];
};
isDraggedRowSelected = (selectedRows, rowDragSource) => {
if (selectedRows && selectedRows.length > 0) {
let key = this.props.rowKey;
return selectedRows.filter(r => r[key] === rowDragSource.data[key]).length > 0;
}
return false;
};
reorderRows = (e) => {
let selectedRows = Selectors.getSelectedRowsByKey({rowKey: this.props.rowKey, selectedKeys: this.state.selectedIds, rows: this.state.rows});
let draggedRows = this.isDraggedRowSelected(selectedRows, e.rowSource) ? selectedRows : [e.rowSource.data];
let undraggedRows = this.state.rows.filter(function(r) {
return draggedRows.indexOf(r) === -1;
});
let args = [e.rowTarget.idx, 0].concat(draggedRows);
Array.prototype.splice.apply(undraggedRows, args);
this.setState({rows: undraggedRows});
};
onRowsSelected = (rows) => {
this.setState({selectedIds: this.state.selectedIds.concat(rows.map(r => r.row[this.props.rowKey]))});
};
onRowsDeselected = (rows) => {
let rowIds = rows.map(r => r.row[this.props.rowKey]);
this.setState({selectedIds: this.state.selectedIds.filter(i => rowIds.indexOf(i) === -1 )});
};
render() {
return (
<DraggableContainer
onHeaderDrop={()=>{console.log('column dropped');}}
>
<Container>
<ReactDataGrid
enableCellSelection={true}
rowActionsCell={RowActionsCell}
columns={this._columns}
rowGetter={this.rowGetter}
rowsCount={this.state.rows.length}
minHeight={500}
rowRenderer={<RowRenderer onRowDrop={this.reorderRows}/>}
rowSelection={{
showCheckbox: true,
enableShiftSelect: true,
onRowsSelected: this.onRowsSelected,
onRowsDeselected: this.onRowsDeselected,
selectBy: {
keys: {rowKey: this.props.rowKey, values: this.state.selectedIds}
}
}}/>
</Container>
</DraggableContainer>);
}
}
module.exports = exampleWrapper({
WrappedComponent: Example,
exampleName: 'Row Reordering',
exampleDescription: 'This examples demonstrates how single or multiple rows can be dragged to a different positions using components from Draggable React Addons',
examplePath: './scripts/example23-row-reordering.js'
});
I went through their documentation but could not find any place where they say these two features can't use together. But in their examples does not provide any example for this.Any example code for documentation describes how to use these two features together would be greatly appreciated.