chore: add-vue3-performance-demo
This commit is contained in:
Родитель
91b002b490
Коммит
9dc23f2e44
|
@ -0,0 +1,23 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -0,0 +1,24 @@
|
|||
# vue3-grid-performance
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "vue3-grid-performance",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@progress/kendo-data-query": "^1.6.0",
|
||||
"@progress/kendo-theme-default": "^5.5.0",
|
||||
"@progress/kendo-vue-grid": "^3.4.1",
|
||||
"@progress/kendo-vue-inputs": "^3.4.1",
|
||||
"@progress/kendo-vue-intl": "^3.4.1",
|
||||
"core-js": "^3.8.3",
|
||||
"vue": "^3.2.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
"@babel/eslint-parser": "^7.12.16",
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "@babel/eslint-parser"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"not ie 11"
|
||||
]
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<img alt="Vue logo" src="./assets/logo.png">
|
||||
<HelloWorld msg="Welcome to Your Vue.js App"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
HelloWorld
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<span :class="[currentTrends.negative ? 'red' : 'green']">
|
||||
{{ formattedNumber }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { provideIntlService } from '@progress/kendo-vue-intl';
|
||||
import { trends } from './utils';
|
||||
|
||||
export default {
|
||||
inject: {
|
||||
kendoIntlService: { default: null },
|
||||
},
|
||||
props: {
|
||||
dataItem: Object,
|
||||
field: String,
|
||||
},
|
||||
computed: {
|
||||
currentTrends() {
|
||||
return trends(this.dataItem);
|
||||
},
|
||||
formattedNumber: function () {
|
||||
return provideIntlService(this).formatNumber(
|
||||
this.dataItem[this.field],
|
||||
this.dataItem[this.field] === 'Change' ? 'n5' : '0.##'
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,290 @@
|
|||
<template>
|
||||
<div>
|
||||
<Grid ref="grid" :style="{ height: '650px', width: '1300px' }" :data-items="processedData" :columns="columns"
|
||||
:column-menu="showColumnMenu" :groupable="groupable" :group="group"
|
||||
:column-virtualization="enableColumnVirtualization" :scrollable="'virtual'" :skip="skip" :take="take"
|
||||
:total="processedData.length" @datastatechange="onDataStateChange" :data-item-key="'ID'"
|
||||
:key="enableColumnVirtualization" :row-height="40">
|
||||
<template v-slot:tickerTemplate="{ props }">
|
||||
<td>
|
||||
<ticker :data-item="props.dataItem" :field="props.field"></ticker>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:priceTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<price :data-item="props.dataItem" :field="props.field"></price>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:pricechangepercentageTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<pricechange :data-item="props.dataItem" :field="props.field"></pricechange>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:pricechangeTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<pricechange :data-item="props.dataItem" :field="props.field"></pricechange>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:highpriceTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<price :data-item="props.dataItem" :field="props.field"></price>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:lowpriceTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<price :data-item="props.dataItem" :field="props.field"></price>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:volumeTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<volume :data-item="props.dataItem" :field="props.field"></volume>
|
||||
</td>
|
||||
</template>
|
||||
<template v-slot:ratingTemplate="{ props }">
|
||||
<td class="text-center">
|
||||
<rating :data-item="props.dataItem" :field="props.field"></rating>
|
||||
</td>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Grid } from '@progress/kendo-vue-grid';
|
||||
import { process } from '@progress/kendo-data-query';
|
||||
import TickerComponent from './TickerComponent.vue';
|
||||
import PriceComponent from './PriceComponent.vue';
|
||||
import ChangePriceComponent from './ChangePriceComponent.vue';
|
||||
import VolumeComponent from './VolumeComponent.vue';
|
||||
import RatingComponent from './RatingComponent.vue';
|
||||
|
||||
const columnsData = [
|
||||
{
|
||||
field: 'Stock',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
field: 'Price',
|
||||
title: 'LAST',
|
||||
width: 120,
|
||||
cell: 'priceTemplate',
|
||||
},
|
||||
{
|
||||
field: 'Change(%)',
|
||||
title: 'CHG %',
|
||||
width: 90,
|
||||
cell: 'pricechangepercentageTemplate',
|
||||
},
|
||||
{
|
||||
field: 'Change',
|
||||
title: 'CHG',
|
||||
width: 90,
|
||||
cell: 'pricechangeTemplate',
|
||||
},
|
||||
{
|
||||
field: 'High(D)',
|
||||
title: 'High',
|
||||
width: 110,
|
||||
cell: 'highpriceTemplate',
|
||||
},
|
||||
{
|
||||
field: 'Low(D)',
|
||||
title: 'LOW',
|
||||
width: 110,
|
||||
cell: 'lowpriceTemplate',
|
||||
},
|
||||
{
|
||||
field: 'Volume',
|
||||
title: 'VOL',
|
||||
width: 90,
|
||||
cell: 'volumeTemplate',
|
||||
},
|
||||
{
|
||||
title: 'RATING',
|
||||
cell: 'ratingTemplate',
|
||||
width: 130,
|
||||
},
|
||||
{ field: 'Country', width: 110 },
|
||||
{ field: 'City', width: 100 },
|
||||
{ field: 'Category', width: 120 },
|
||||
{ field: 'Type', width: 100 },
|
||||
{ field: 'Settlement', width: 100 },
|
||||
{ field: 'Industry', width: 100, filterable: false },
|
||||
{ field: 'Sector', width: 120, filterable: false, resizable: true },
|
||||
{ field: 'SubSector', width: 100, filterable: false },
|
||||
{ field: 'SectorType', width: 90, filterable: false },
|
||||
{ field: 'SecurityCode', width: 170, filterable: false, resizable: true },
|
||||
{ field: 'FullName', width: 60, filterable: false },
|
||||
{ field: 'FitchRating', width: 60, filterable: false },
|
||||
{ field: 'DBRSRating', width: 60, filterable: false },
|
||||
{ field: 'Address', width: 90, filterable: false },
|
||||
{ field: 'Currency', width: 60, filterable: false },
|
||||
{ field: 'SecurityCode', width: 120, filterable: false },
|
||||
{ field: 'SectorCode', width: 80, filterable: false },
|
||||
{ field: 'Phone', width: 100, filterable: false },
|
||||
{ field: 'Ticker', width: 60, filterable: false },
|
||||
{ field: 'Cpn', width: 80, filterable: false },
|
||||
{ field: 'Maturity', width: 120, filterable: false },
|
||||
{ field: 'KRD_10YR', width: 110, filterable: false },
|
||||
{ field: 'CUSIP', width: 90, filterable: false },
|
||||
{ field: 'KRD_5YR', width: 50, filterable: false },
|
||||
{ field: 'KRD_1YR', width: 80, filterable: false },
|
||||
{ field: 'Industry', width: 100, filterable: false },
|
||||
{ field: 'Sector', width: 120, filterable: false, resizable: true },
|
||||
{ field: 'SubSector', width: 100, filterable: false },
|
||||
{ field: 'SectorType', width: 90, filterable: false },
|
||||
{ field: 'SecurityCode', width: 170, filterable: false, resizable: true },
|
||||
{ field: 'FullName', width: 60, filterable: false },
|
||||
{ field: 'FitchRating', width: 60, filterable: false },
|
||||
{ field: 'DBRSRating', width: 60, filterable: false },
|
||||
{ field: 'Address', width: 90, filterable: false },
|
||||
{ field: 'Currency', width: 60, filterable: false },
|
||||
{ field: 'SecurityCode', width: 120, filterable: false },
|
||||
{ field: 'SectorCode', width: 80, filterable: false },
|
||||
{ field: 'Phone', width: 100, filterable: false },
|
||||
{ field: 'Ticker', width: 60, filterable: false },
|
||||
{ field: 'Cpn', width: 80, filterable: false },
|
||||
{ field: 'Maturity', width: 120, filterable: false },
|
||||
{ field: 'KRD_10YR', width: 110, filterable: false },
|
||||
{ field: 'CUSIP', width: 90, filterable: false },
|
||||
{ field: 'KRD_5YR', width: 50, filterable: false },
|
||||
{ field: 'KRD_1YR', width: 80, filterable: false },
|
||||
{ field: 'Industry', width: 100, filterable: false },
|
||||
{ field: 'Sector', width: 120, filterable: false, resizable: true },
|
||||
{ field: 'SubSector', width: 100, filterable: false },
|
||||
{ field: 'SectorType', width: 90, filterable: false },
|
||||
{ field: 'SecurityCode', width: 170, filterable: false, resizable: true },
|
||||
{ field: 'FullName', width: 60, filterable: false },
|
||||
{ field: 'FitchRating', width: 60, filterable: false },
|
||||
{ field: 'DBRSRating', width: 60, filterable: false },
|
||||
{ field: 'Address', width: 90, filterable: false },
|
||||
{ field: 'Currency', width: 60, filterable: false },
|
||||
{ field: 'SecurityCode', width: 120, filterable: false },
|
||||
{ field: 'SectorCode', width: 80, filterable: false },
|
||||
{ field: 'Phone', width: 100, filterable: false },
|
||||
{ field: 'Ticker', width: 60, filterable: false },
|
||||
{ field: 'Cpn', width: 80, filterable: false },
|
||||
{ field: 'Maturity', width: 120, filterable: false },
|
||||
{ field: 'KRD_10YR', width: 110, filterable: false },
|
||||
{ field: 'CUSIP', width: 90, filterable: false },
|
||||
{ field: 'KRD_5YR', width: 50, filterable: false },
|
||||
{ field: 'KRD_1YR', width: 80, filterable: false },
|
||||
{ field: 'Industry', width: 100, filterable: false },
|
||||
{ field: 'Sector', width: 120, filterable: false, resizable: true },
|
||||
{ field: 'SubSector', width: 100, filterable: false },
|
||||
{ field: 'SectorType', width: 90, filterable: false },
|
||||
{ field: 'SecurityCode', width: 170, filterable: false, resizable: true },
|
||||
{ field: 'FullName', width: 60, filterable: false },
|
||||
{ field: 'FitchRating', width: 60, filterable: false },
|
||||
{ field: 'DBRSRating', width: 60, filterable: false },
|
||||
{ field: 'Address', width: 90, filterable: false },
|
||||
{ field: 'Currency', width: 60, filterable: false },
|
||||
{ field: 'SecurityCode', width: 120, filterable: false },
|
||||
{ field: 'SectorCode', width: 80, filterable: false },
|
||||
{ field: 'Phone', width: 100, filterable: false },
|
||||
{ field: 'Ticker', width: 60, filterable: false },
|
||||
{ field: 'Cpn', width: 80, filterable: false },
|
||||
{ field: 'Maturity', width: 120, filterable: false },
|
||||
{ field: 'KRD_10YR', width: 110, filterable: false },
|
||||
{ field: 'CUSIP', width: 90, filterable: false },
|
||||
{ field: 'KRD_5YR', width: 50, filterable: false },
|
||||
{ field: 'KRD_1YR', width: 80, filterable: false },
|
||||
{ field: 'Industry', width: 100, filterable: false },
|
||||
{ field: 'Sector', width: 120, filterable: false, resizable: true },
|
||||
{ field: 'SubSector', width: 100, filterable: false },
|
||||
{ field: 'SectorType', width: 90, filterable: false },
|
||||
{ field: 'SecurityCode', width: 170, filterable: false, resizable: true },
|
||||
{ field: 'FullName', width: 60, filterable: false },
|
||||
{ field: 'FitchRating', width: 60, filterable: false },
|
||||
{ field: 'DBRSRating', width: 60, filterable: false },
|
||||
{ field: 'Address', width: 90, filterable: false },
|
||||
{ field: 'Currency', width: 60, filterable: false },
|
||||
{ field: 'SecurityCode', width: 120, filterable: false },
|
||||
{ field: 'SectorCode', width: 80, filterable: false },
|
||||
{ field: 'Phone', width: 100, filterable: false },
|
||||
{ field: 'Ticker', width: 60, filterable: false },
|
||||
{ field: 'Cpn', width: 80, filterable: false },
|
||||
{ field: 'Maturity', width: 120, filterable: false },
|
||||
{ field: 'KRD_10YR', width: 110, filterable: false },
|
||||
{ field: 'CUSIP', width: 90, filterable: false },
|
||||
{ field: 'KRD_5YR', width: 50, filterable: false },
|
||||
{ field: 'KRD_1YR', width: 80, filterable: false },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Grid: Grid,
|
||||
price: PriceComponent,
|
||||
pricechange: ChangePriceComponent,
|
||||
ticker: TickerComponent,
|
||||
volume: VolumeComponent,
|
||||
rating: RatingComponent,
|
||||
},
|
||||
props: {
|
||||
gridData: Array,
|
||||
showColumnMenu: Boolean,
|
||||
groupable: Boolean,
|
||||
enableColumnVirtualization: Boolean
|
||||
},
|
||||
mounted() {
|
||||
this.columns = columnsData;
|
||||
this.processedData = this.processData();
|
||||
},
|
||||
watch: {
|
||||
gridData() {
|
||||
this.processedData = this.processData();
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [],
|
||||
skip: 0,
|
||||
take: 25,
|
||||
group: [],
|
||||
processedData: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
pageChange(event) {
|
||||
this.skip = event.page.skip;
|
||||
this.take = event.page.take;
|
||||
},
|
||||
onDataStateChange(event) {
|
||||
console.log("DataStateChange")
|
||||
this.createAppState(event.data);
|
||||
},
|
||||
createAppState(dataState) {
|
||||
this.group = dataState.group;
|
||||
this.take = dataState.take;
|
||||
this.skip = dataState.skip;
|
||||
this.processedData = this.processData();
|
||||
},
|
||||
processData() {
|
||||
return process(this.gridData, {
|
||||
take: this.take,
|
||||
skip: this.skip,
|
||||
group: this.group,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
td.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: #37b400;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class='row m-3'>
|
||||
<div class='col-3'>
|
||||
<div :style="{ minWidth: '140px' }">
|
||||
<Switch @change="onColumnMenuChange" :checked="showColumnMenu" />
|
||||
Column Menu
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-3'>
|
||||
<div :style="{ minWidth: '140px' }">
|
||||
<Switch @change="onColumnVirtualizationChange" :checked="enableColumnVirtualization" />
|
||||
Column Virtualization
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-3'>
|
||||
<div :style="{ minWidth: '140px' }">
|
||||
<Switch @change="onGroupingChange" />
|
||||
Grouping
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='row m-3'>
|
||||
<div class='col-3'>
|
||||
<label>
|
||||
Records: {{ currentValue }} <br />
|
||||
<Slider :min="0" :max="1000000" :step="VOLUME_STEP" :defaultValue="VOLUME_INITIAL" @change="onVolumeChange"
|
||||
:disabled="liveUpdating" />
|
||||
</label>
|
||||
</div>
|
||||
<div class='col-3'>
|
||||
<label>
|
||||
Frequency: {{ currentFrequency }} ms <br />
|
||||
<Slider :min="100" :max="3000" :step="10" :defaultValue="FREQUENCY_STEP" @change="onFrequencyChange"
|
||||
:disabled="liveUpdating" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class='row m-3'>
|
||||
<div class='col'>
|
||||
<ButtonGroup>
|
||||
<KButton v-for="(btn, key) in buttonsData" :toggable="true" :icon="btn.icon" :key="key"
|
||||
:style="{ width: '200px' }" :name="key" @click="onButtonGroupClick"> {{ btn.title }}</KButton>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<grid :grid-data="data" :show-column-menu="showColumnMenu" :groupable="groupable"
|
||||
:enable-column-virtualization="enableColumnVirtualization"></grid>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { RadioGroup } from '@progress/kendo-vue-inputs';
|
||||
import Grid from './Grid.vue';
|
||||
import { Slider, Switch } from "@progress/kendo-vue-inputs";
|
||||
import { Button, ButtonGroup } from "@progress/kendo-vue-buttons";
|
||||
import { FinancialData } from './financial-data';
|
||||
import { updateRandomPrices, updateAllPrices } from './services';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Grid,
|
||||
Slider, Switch,
|
||||
KButton: Button,
|
||||
ButtonGroup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: [],
|
||||
intervalRef: null,
|
||||
showColumnMenu: true,
|
||||
enableColumnVirtualization: true,
|
||||
liveUpdating: false,
|
||||
VOLUME_STEP: 1000,
|
||||
VOLUME_INITIAL: 10000,
|
||||
FREQUENCY_STEP: 100,
|
||||
currentFrequency: 100,
|
||||
currentValue: 100,
|
||||
groupable: false,
|
||||
buttonsData: {
|
||||
live: {
|
||||
title: 'Live Prices',
|
||||
icon: 'refresh'
|
||||
},
|
||||
liveAll: {
|
||||
title: 'Live All Prices',
|
||||
icon: 'refresh'
|
||||
},
|
||||
stop: {
|
||||
title: 'Stop',
|
||||
icon: 'stop'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.generateNewData();
|
||||
},
|
||||
methods: {
|
||||
generateNewData() {
|
||||
const financialData = new FinancialData();
|
||||
this.data = financialData.generateData(this.currentValue);
|
||||
},
|
||||
onFrequencyChange(e) {
|
||||
this.currentFrequency =
|
||||
Math.floor(e.value / this.FREQUENCY_STEP) * this.FREQUENCY_STEP
|
||||
},
|
||||
startDataGeneration() {
|
||||
this.dataReset();
|
||||
this.startLiveUpdate(this.currentFrequency);
|
||||
},
|
||||
dataReset() {
|
||||
clearInterval(this.intervalRef);
|
||||
},
|
||||
startLiveUpdate(interval) {
|
||||
clearInterval(this.intervalRef);
|
||||
this.intervalRef = setInterval(() => {
|
||||
this.gridData = updateRandomPrices(this.data);
|
||||
}, interval);
|
||||
},
|
||||
startLiveUpdateAll(interval) {
|
||||
console.log(this.intervalRef)
|
||||
clearInterval(this.intervalRef);
|
||||
this.intervalRef = setInterval(() => {
|
||||
this.gridData = updateAllPrices(this.data);
|
||||
}, interval);
|
||||
},
|
||||
stopLiveUpdate() {
|
||||
clearInterval(this.intervalRef);
|
||||
},
|
||||
onColumnMenuChange() {
|
||||
this.showColumnMenu = !this.showColumnMenu;
|
||||
},
|
||||
onColumnVirtualizationChange() {
|
||||
this.enableColumnVirtualization = !this.enableColumnVirtualization;
|
||||
},
|
||||
onGroupingChange() {
|
||||
this.groupable = !this.groupable;
|
||||
},
|
||||
onVolumeChange(e) {
|
||||
this.currentValue = Math.floor(e.value / this.VOLUME_STEP) * this.VOLUME_STEP;
|
||||
this.generateNewData();
|
||||
},
|
||||
onButtonGroupClick(event) {
|
||||
const currentButton = event.currentTarget.name;
|
||||
|
||||
this.selectedButton = currentButton;
|
||||
switch (currentButton) {
|
||||
case "live":
|
||||
this.startLiveUpdate(this.currentFrequency);
|
||||
this.liveUpdating = true;
|
||||
break;
|
||||
case "liveAll":
|
||||
this.startLiveUpdateAll(this.currentFrequency);
|
||||
this.liveUpdating = true;
|
||||
break;
|
||||
case "stop":
|
||||
this.stopLiveUpdate();
|
||||
this.liveUpdating = false;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<span>{{ formattedNumber }} </span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { provideIntlService } from '@progress/kendo-vue-intl';
|
||||
|
||||
export default {
|
||||
inject: {
|
||||
kendoIntlService: { default: null },
|
||||
},
|
||||
props: {
|
||||
dataItem: Object,
|
||||
field: String,
|
||||
},
|
||||
computed: {
|
||||
formattedNumber: function () {
|
||||
return provideIntlService(this).formatNumber(
|
||||
this.dataItem[this.field],
|
||||
'n5'
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<div
|
||||
:class="[
|
||||
rating === 'Buy' || rating === 'Strong Buy'
|
||||
? 'green text-bold'
|
||||
: 'red text-bold',
|
||||
]"
|
||||
>
|
||||
{{ rating }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { trends } from './utils';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
dataItem: Object,
|
||||
field: String,
|
||||
},
|
||||
computed: {
|
||||
rating() {
|
||||
const currentTrends = trends(this.$props.dataItem);
|
||||
return currentTrends.strongNegative
|
||||
? 'Strong Sell'
|
||||
: currentTrends.negative
|
||||
? 'Sell'
|
||||
: currentTrends.positive
|
||||
? 'Buy'
|
||||
: currentTrends.strongPositive
|
||||
? 'Strong Buy'
|
||||
: 'Neutral';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<div>
|
||||
<img
|
||||
:alt="`${dataItem.Ticker} icon`"
|
||||
:src="`./${dataItem.Ticker}.png`"
|
||||
/><span
|
||||
:style="{
|
||||
color: '#4B5FFA',
|
||||
marginLeft: '5px',
|
||||
fontWeight: 'bold',
|
||||
}"
|
||||
>{{ dataItem[field] }}</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
dataItem: Object,
|
||||
field: String,
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<span> {{ formattedNumber }} </span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
inject: {
|
||||
kendoIntlService: { default: null },
|
||||
},
|
||||
props: {
|
||||
dataItem: Object,
|
||||
field: String,
|
||||
},
|
||||
computed: {
|
||||
formattedNumber: function () {
|
||||
return this.dataItem[this.field];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.7 KiB |
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,422 @@
|
|||
/* tslint:disable */
|
||||
export const COUNTRIES = [
|
||||
{
|
||||
"Country": "America",
|
||||
"Cities": ["New York", "Chicago", "Dallas", "Los Angeles", "Boston", "Austin", "Florida"]
|
||||
},
|
||||
{
|
||||
"Country": "Germany",
|
||||
"Cities": ["Dortmund", "Stuttgard", "München", "Berlin", "Hamburg"]
|
||||
},
|
||||
{
|
||||
"Country": "United Kingdom",
|
||||
"Cities": ["Manchester", "Liverpool", "Sheffield", "Leeds", "Birmingham", "London"]
|
||||
},
|
||||
{
|
||||
"Country": "Italy",
|
||||
"Cities": ["Milano", "Firenze", "Roma", "Napoli", "Catania", "Palermo", "Venezia"]
|
||||
},
|
||||
{
|
||||
"Country": "France",
|
||||
"Cities": ["Nantes", "Paris", "Toulouse", "Montpellier", "Marseille", "Nice", "Lyon"]
|
||||
},
|
||||
{
|
||||
"Country": "Spain",
|
||||
"Cities": ["Madrid", "Zaragoza", "València", "Murcia", "Málaga", "Barcelona"]
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
export const DealType = [
|
||||
"Buy", "Sell"
|
||||
]
|
||||
|
||||
export const Stock = [
|
||||
"OX", "USD", "SHIB", "TETHERUS", "XEC", "18C", "BITCOIN", "ETHERIUM", "INCH", "BUSD", "GBP", "EUR"
|
||||
]
|
||||
|
||||
export const Settlement = [
|
||||
"Deliverable", "Cash"
|
||||
]
|
||||
|
||||
export const MOCKFINANCEDATA = [
|
||||
{
|
||||
"Category": "Test Data",
|
||||
"Industry": "Informational technology",
|
||||
"Sector": "Technology",
|
||||
"SubSector": "Machine learning",
|
||||
"SectorType": "PRIVATE",
|
||||
// tslint:disable-next-line:object-literal-sort-keys
|
||||
"Type": "DEFAULT",
|
||||
"FullName": "Progress Software",
|
||||
"Location": "Boston",
|
||||
"FitchRating": "Private",
|
||||
"DBRSRating": "Private",
|
||||
"Currency": "USD",
|
||||
"SecurityCode": "12345678910 IT",
|
||||
"SectorCode": "IT",
|
||||
"CUSIP": "987654321",
|
||||
"Ticker": "PGRS",
|
||||
"Cpn": "40.875",
|
||||
"Maturity": "1981",
|
||||
"KRD_5YR": 2.00006,
|
||||
"Address": "Bedford",
|
||||
"Phone": "+1 111 111 111",
|
||||
"Number": 28.302,
|
||||
"KRD_10YR": 0,
|
||||
"KRD_1YR": -0.00187,
|
||||
"SpecialCode": null
|
||||
}];
|
||||
|
||||
export const DATA = [
|
||||
{
|
||||
"Ticker": "OX",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 1281.10,
|
||||
"Price": 1280.7317,
|
||||
"Buy": 1280.7267,
|
||||
"Sell": 1280.7367,
|
||||
"Change": -0.3683,
|
||||
"Change(%)": -0.0287,
|
||||
"Volume": 48387,
|
||||
"High(D)": 1289.50,
|
||||
"Low(D)": 1279.10,
|
||||
"High(Y)": 1306,
|
||||
"Low(Y)": 1047.20,
|
||||
"Start(Y)": 1176.60,
|
||||
"Change On Year(%)": 8.8502
|
||||
},
|
||||
{
|
||||
"Ticker": "USD",
|
||||
"Type": "Silver",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 17.43,
|
||||
"Price": 17.42,
|
||||
"Buy": 17.43,
|
||||
"Sell": 17.43,
|
||||
"Change": -0.01,
|
||||
"Change(%)": -0.0574,
|
||||
"Volume": 11720,
|
||||
"High(D)": 17.51,
|
||||
"Low(D)": 17.37,
|
||||
"High(Y)": 18.06,
|
||||
"Low(Y)": 13.73,
|
||||
"Start(Y)": 15.895,
|
||||
"Change On Year(%)": 9.5942
|
||||
},
|
||||
{
|
||||
"Ticker": "SHIB",
|
||||
"Type": "Copper",
|
||||
"Spread": 0.02,
|
||||
"Open Price": 2.123,
|
||||
"Price": 2.113,
|
||||
"Buy": 2.123,
|
||||
"Sell": 2.123,
|
||||
"Change": -0.01,
|
||||
"Change(%)": -0.471,
|
||||
"Volume": 28819,
|
||||
"High(D)": 2.16,
|
||||
"Low(D)": 2.11,
|
||||
"High(Y)": 2.94,
|
||||
"Low(Y)": 1.96,
|
||||
"Start(Y)": 2.45,
|
||||
"Change On Year(%)": -13.7551
|
||||
},
|
||||
{
|
||||
"Ticker": "TETHERUS",
|
||||
"Type": "Platinum",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 1071.60,
|
||||
"Price": 1071.0993,
|
||||
"Buy": 1071.0943,
|
||||
"Sell": 1071.1043,
|
||||
"Change": -0.5007,
|
||||
"Change(%)": -0.0467,
|
||||
"Volume": 3039,
|
||||
"High(D)": 1081.20,
|
||||
"Low(D)": 1070.50,
|
||||
"High(Y)": 1120.60,
|
||||
"Low(Y)": 812.40,
|
||||
"Start(Y)": 966.50,
|
||||
"Change On Year(%)": 10.8225
|
||||
},
|
||||
{
|
||||
"Ticker": "XEC",
|
||||
"Type": "Palladium",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 600.55,
|
||||
"Price": 601.0005,
|
||||
"Buy": 600.9955,
|
||||
"Sell": 601.0055,
|
||||
"Change": 0.4505,
|
||||
"Change(%)": 0.075,
|
||||
"Volume": 651,
|
||||
"High(D)": 607.20,
|
||||
"Low(D)": 598.40,
|
||||
"High(Y)": 690,
|
||||
"Low(Y)": 458.6,
|
||||
"Start(Y)": 574.3,
|
||||
"Change On Year(%)": 4.6492
|
||||
},
|
||||
{
|
||||
"Ticker": "18C",
|
||||
"Type": "Oil",
|
||||
"Spread": 0.015,
|
||||
"Open Price": 45.54,
|
||||
"Price": 45.7899,
|
||||
"Buy": 45.7824,
|
||||
"Sell": 45.7974,
|
||||
"Change": 0.2499,
|
||||
"Change(%)": 0.5487,
|
||||
"Volume": 107196,
|
||||
"High(D)": 45.94,
|
||||
"Low(D)": 45.00,
|
||||
"High(Y)": 65.28,
|
||||
"Low(Y)": 30.79,
|
||||
"Start(Y)": 48.035,
|
||||
"Change On Year(%)": -4.6739
|
||||
},
|
||||
{
|
||||
"Ticker": "BITCOIN",
|
||||
"Type": "Brent",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 46.06,
|
||||
"Price": 46.05,
|
||||
"Buy": 46.06,
|
||||
"Sell": 46.06,
|
||||
"Change": -0.01,
|
||||
"Change(%)": -0.0217,
|
||||
"Volume": 59818,
|
||||
"High(D)": 46.48,
|
||||
"Low(D)": 45.60,
|
||||
"High(Y)": 71.14,
|
||||
"Low(Y)": 30.02,
|
||||
"Start(Y)": 50.58,
|
||||
"Change On Year(%)": -8.9561
|
||||
},
|
||||
{
|
||||
"Ticker": "ETHERIUM",
|
||||
"Type": "Natural Gas",
|
||||
"Spread": 0.02,
|
||||
"Open Price": 2.094,
|
||||
"Price": 2.104,
|
||||
"Buy": 2.094,
|
||||
"Sell": 2.094,
|
||||
"Change": 0.01,
|
||||
"Change(%)": 0.4776,
|
||||
"Volume": 2783,
|
||||
"High(D)": 2.11,
|
||||
"Low(D)": 2.09,
|
||||
"High(Y)": 3.20,
|
||||
"Low(Y)": 1.84,
|
||||
"Start(Y)": 2.52,
|
||||
"Change On Year(%)": -16.5079
|
||||
},
|
||||
{
|
||||
"Ticker": "INCH",
|
||||
"Type": "RBOB Gas",
|
||||
"Spread": 0.015,
|
||||
"Open Price": 1.5086,
|
||||
"Price": 1.9532,
|
||||
"Buy": 1.9457,
|
||||
"Sell": 1.9607,
|
||||
"Change": 0.4446,
|
||||
"Change(%)": 29.4686,
|
||||
"Volume": 2646,
|
||||
"High(D)": 1.9532,
|
||||
"Low(D)": 1.50,
|
||||
"High(Y)": 2.05,
|
||||
"Low(Y)": 1.15,
|
||||
"Start(Y)": 1.60,
|
||||
"Change On Year(%)": 22.0727
|
||||
},
|
||||
{
|
||||
"Ticker": "BUSD",
|
||||
"Type": "Diesel",
|
||||
"Spread": 0.015,
|
||||
"Open Price": 1.3474,
|
||||
"Price": 1.3574,
|
||||
"Buy": 1.3474,
|
||||
"Sell": 1.3474,
|
||||
"Change": 0.01,
|
||||
"Change(%)": 0.7422,
|
||||
"Volume": 2971,
|
||||
"High(D)": 1.36,
|
||||
"Low(D)": 1.34,
|
||||
"High(Y)": 2.11,
|
||||
"Low(Y)": 0.92,
|
||||
"Start(Y)": 1.515,
|
||||
"Change On Year(%)": -10.4026
|
||||
},
|
||||
{
|
||||
"Ticker": "GBP",
|
||||
"Type": "Ethanol",
|
||||
"Spread": 0.01,
|
||||
"Open Price": 1.512,
|
||||
"Price": 2.7538,
|
||||
"Buy": 2.7488,
|
||||
"Sell": 2.7588,
|
||||
"Change": 1.2418,
|
||||
"Change(%)": 82.1323,
|
||||
"Volume": 14,
|
||||
"High(D)": 2.7538,
|
||||
"Low(D)": 1.1168,
|
||||
"High(Y)": 2.7538,
|
||||
"Low(Y)": 1.1168,
|
||||
"Start(Y)": 1.475,
|
||||
"Change On Year(%)": 86.7011
|
||||
},
|
||||
{
|
||||
"Ticker": "EUR",
|
||||
"Type": "Uranium",
|
||||
"Spread": 0.02,
|
||||
"Open Price": 27.55,
|
||||
"Price": 27.58,
|
||||
"Buy": 27.55,
|
||||
"Sell": 27.55,
|
||||
"Change": 0.03,
|
||||
"Change(%)": 0.1089,
|
||||
"Volume": 12,
|
||||
"High(D)": 27.55,
|
||||
"Low(D)": 27.55,
|
||||
"High(Y)": 29.32,
|
||||
"Low(Y)": 21.28,
|
||||
"Start(Y)": 25.30,
|
||||
"Change On Year(%)": 9.0119
|
||||
}
|
||||
];
|
||||
|
||||
/* tslint:enable */
|
||||
export class FinancialData {
|
||||
generateData(count) {
|
||||
console.time('generateData');
|
||||
const currData = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const rand = Math.floor(Math.random() * Math.floor(DATA.length));
|
||||
const dataObj = Object.assign({}, DATA[rand]);
|
||||
|
||||
dataObj.Settlement = Settlement[this.generateRandomNumber(0, 1)];
|
||||
dataObj.Stock = Stock[this.generateRandomNumber(0, 11)];
|
||||
const country = COUNTRIES[this.generateRandomNumber(0, 5)];
|
||||
dataObj.Country = country.Country;
|
||||
dataObj.City = this.randomizeCity(country);
|
||||
// for (let y = 0; y < 80; y++) {
|
||||
// dataObj["Text" + y] = "Text";
|
||||
// }
|
||||
|
||||
for (const mockData of MOCKFINANCEDATA) {
|
||||
for (const prop in mockData) {
|
||||
if (Object.prototype.hasOwnProperty.call(mockData, prop)) {
|
||||
dataObj[prop] = mockData[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataObj.ID = i;
|
||||
this.randomizeObjectData(dataObj);
|
||||
currData.push(dataObj);
|
||||
}
|
||||
console.timeEnd('generateData');
|
||||
return currData;
|
||||
}
|
||||
|
||||
updateAllPrices(data) {
|
||||
const currData = [];
|
||||
for (const dataRow of data) {
|
||||
const dataObj = Object.assign({}, dataRow);
|
||||
this.randomizeObjectData(dataObj);
|
||||
currData.push(dataObj);
|
||||
}
|
||||
return currData;
|
||||
}
|
||||
|
||||
updateRandomPrices(data) {
|
||||
const currData = data.slice(0, data.length + 1);
|
||||
// let y = 0;
|
||||
for (let i = Math.round(Math.random() * 10); i < data.length; i += Math.round(Math.random() * 10)) {
|
||||
const dataObj = Object.assign({}, data[i]);
|
||||
this.randomizeObjectData(dataObj);
|
||||
currData[i] = dataObj;
|
||||
// y++;
|
||||
}
|
||||
// return {data: currData, recordsUpdated: y };
|
||||
return currData;
|
||||
}
|
||||
|
||||
updateRandomPrices2(data) {
|
||||
const currData = data.slice(0, data.length + 1);
|
||||
let y = 0;
|
||||
for (let i = Math.round(Math.random() * 10); i < data.length; i += Math.round(Math.random() * 10)) {
|
||||
const dataObj = Object.assign({}, data[i]);
|
||||
this.randomizeObjectData(dataObj);
|
||||
currData[i] = dataObj;
|
||||
y++;
|
||||
}
|
||||
return { data: currData, recordsUpdated: y };
|
||||
}
|
||||
|
||||
randomizeObjectData(dataObj) {
|
||||
const changeP = 'Change(%)';
|
||||
const res = this.generateNewPrice(dataObj.Price);
|
||||
dataObj.Change = res.Price - dataObj.Price;
|
||||
dataObj.Price = res.Price;
|
||||
dataObj[changeP] = res.ChangePercent;
|
||||
}
|
||||
|
||||
generateNewPrice(oldPrice) {
|
||||
const rnd = parseFloat(Math.random().toFixed(2));
|
||||
const volatility = 2;
|
||||
let newPrice = 0;
|
||||
|
||||
let changePercent = 2 * volatility * rnd;
|
||||
if (changePercent > volatility) {
|
||||
changePercent -= (2 * volatility);
|
||||
}
|
||||
|
||||
const changeAmount = oldPrice * (changePercent / 100);
|
||||
newPrice = oldPrice + changeAmount;
|
||||
|
||||
const result = { Price: 0, ChangePercent: 0 };
|
||||
result.Price = parseFloat(newPrice.toFixed(2));
|
||||
result.ChangePercent = parseFloat(changePercent.toFixed(2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
generateRandomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
randomizeCity(country) {
|
||||
let city;
|
||||
switch (country.Country) {
|
||||
case 'America': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 6)];
|
||||
break;
|
||||
}
|
||||
case 'Germany': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 4)];
|
||||
break;
|
||||
}
|
||||
case 'United Kingdom': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 5)];
|
||||
break;
|
||||
}
|
||||
case 'Italy': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 6)];
|
||||
break;
|
||||
}
|
||||
case 'France': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 6)];
|
||||
break;
|
||||
}
|
||||
case 'Spain': {
|
||||
city = country.Cities[this.generateRandomNumber(0, 5)];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return city;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './MainComponent.vue'
|
||||
import '@progress/kendo-theme-default'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,52 @@
|
|||
export const updateRandomPrices = (data) => {
|
||||
const newData = data.slice();
|
||||
|
||||
for (
|
||||
let i = Math.round(Math.random() * 10);
|
||||
i < newData.length;
|
||||
i += Math.round(Math.random() * 10)
|
||||
) {
|
||||
randomizeObjectData(newData[i]);
|
||||
}
|
||||
|
||||
return newData;
|
||||
};
|
||||
export const updateAllPrices = (data) => {
|
||||
const newData = data.slice();
|
||||
|
||||
for (const dataRow of newData) {
|
||||
randomizeObjectData(dataRow);
|
||||
}
|
||||
|
||||
return newData;
|
||||
};
|
||||
export const randomizeObjectData = (dataObj) => {
|
||||
const changeP = 'Change(%)';
|
||||
const res = generateNewPrice(dataObj.Price);
|
||||
dataObj.Change = res.Price - dataObj.Price;
|
||||
dataObj.Price = res.Price;
|
||||
dataObj[changeP] = res.ChangePercent;
|
||||
};
|
||||
export const generateNewPrice = (oldPrice) => {
|
||||
let rnd = Math.random();
|
||||
rnd = Math.round(rnd * 100) / 100;
|
||||
const volatility = 2;
|
||||
let newPrice = 0;
|
||||
let changePercent = 2 * volatility * rnd;
|
||||
|
||||
if (changePercent > volatility) {
|
||||
changePercent -= 2 * volatility;
|
||||
}
|
||||
|
||||
const changeAmount = oldPrice * (changePercent / 100);
|
||||
newPrice = oldPrice + changeAmount;
|
||||
newPrice = Math.round(newPrice * 100) / 100;
|
||||
const result = {
|
||||
Price: 0,
|
||||
ChangePercent: 0,
|
||||
};
|
||||
changePercent = Math.round(changePercent * 100) / 100;
|
||||
result.Price = newPrice;
|
||||
result.ChangePercent = changePercent;
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
export const negative = (rowData) => {
|
||||
return rowData['Change(%)'] < 0;
|
||||
};
|
||||
export const positive = (rowData) => {
|
||||
return rowData['Change(%)'] > 0;
|
||||
};
|
||||
export const changeNegative = (rowData) => {
|
||||
return rowData['Change(%)'] < 0 && rowData['Change(%)'] > -1;
|
||||
};
|
||||
export const changePositive = (rowData) => {
|
||||
return rowData['Change(%)'] > 0 && rowData['Change(%)'] < 1;
|
||||
};
|
||||
export const strongPositive = (rowData) => {
|
||||
return rowData['Change(%)'] >= 1;
|
||||
};
|
||||
export const strongNegative = (rowData) => {
|
||||
return rowData['Change(%)'] <= -1;
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
changeNegative,
|
||||
changePositive,
|
||||
negative,
|
||||
positive,
|
||||
strongNegative,
|
||||
strongPositive,
|
||||
} from './trends';
|
||||
|
||||
|
||||
export const trends = (dataItem) => {
|
||||
return {
|
||||
changeNegative: changeNegative(dataItem),
|
||||
changePositive: changePositive(dataItem),
|
||||
negative: negative(dataItem),
|
||||
positive: positive(dataItem),
|
||||
strongNegative: strongNegative(dataItem),
|
||||
strongPositive: strongPositive(dataItem),
|
||||
};
|
||||
};
|
||||
|
Загрузка…
Ссылка в новой задаче