| | |
| | | <template> |
| | | <div class="kline-charts"> |
| | | <ul class="flex px-32 pb-20 box-border justify-between text-grey fontStyle font-26" |
| | | style="border-bottom:1px solid rgba(68,75,88,0.2);"> |
| | | <li v-for="item in timeList" :key="item.id" class="mr-10" :class="{ 'textColor': item.id === timeValue.id }" |
| | | @click="choiceTime(item)">{{ item.text }}</li> |
| | | <ul |
| | | class="flex px-32 pb-20 box-border justify-between text-grey fontStyle font-26" |
| | | style="border-bottom: 1px solid rgba(68, 75, 88, 0.2)" |
| | | > |
| | | <li |
| | | v-for="item in timeList" |
| | | :key="item.id" |
| | | class="mr-10" |
| | | :class="{ textColor: item.id === timeValue.id }" |
| | | @click="choiceTime(item)" |
| | | > |
| | | {{ item.text }} |
| | | </li> |
| | | </ul> |
| | | <div class="relative"> |
| | | <div id="kline" class="h-828"></div> |
| | | <div |
| | | class="flex justify-center items-center text-center text-grey absolute left-0 top-0 w-full h-full z-10 mainBackground" |
| | | v-if="chartLoading"> |
| | | class="flex justify-center items-center text-center text-grey absolute left-0 top-0 w-full h-full z-10 mainBackground" |
| | | v-if="chartLoading" |
| | | > |
| | | <van-loading type="spinner"></van-loading> |
| | | </div> |
| | | </div> |
| | | <ul class="flex px-32 py-20 box-border justify-between text-grey font-26" v-if="showBottom" |
| | | style="border-top:1px solid rgba(68,75,88,0.2);"> |
| | | <li v-for="item in subTechnicalIndicatorTypes" :key="item" class="mr-20" |
| | | :class="{ 'textColor': typeValue === item }" @click="choiceType(item)">{{ item }}</li> |
| | | <ul |
| | | class="flex px-32 py-20 box-border justify-between text-grey font-26" |
| | | v-if="showBottom" |
| | | style="border-top: 1px solid rgba(68, 75, 88, 0.2)" |
| | | > |
| | | <li |
| | | v-for="item in subTechnicalIndicatorTypes" |
| | | :key="item" |
| | | class="mr-20" |
| | | :class="{ textColor: typeValue === item }" |
| | | @click="choiceType(item)" |
| | | > |
| | | {{ item }} |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import { init, dispose } from 'klinecharts' |
| | | let chart = null |
| | | import { _getKline } from '@/API/trade.api' |
| | | import config from './config' |
| | | import { Loading } from 'vant'; |
| | | import { init, dispose } from "klinecharts"; |
| | | let chart = null; |
| | | import { _getKline } from "@/API/trade.api"; |
| | | import config from "./config"; |
| | | import { Loading } from "vant"; |
| | | import { scientificNotationToString } from "@/utils/utis"; |
| | | export default { |
| | | name: 'KlineCharts', |
| | | name: "KlineCharts", |
| | | data() { |
| | | return { |
| | | // symbol: 'btc', |
| | | dealInfo: {},//交易对信息 |
| | | dealInfo: {}, //交易对信息 |
| | | |
| | | timeValue: {}, // 当前k线周期 |
| | | subTechnicalIndicatorTypes: ['MA', 'EMA', 'BOLL', 'VOL', 'MACD', 'KDJ', 'RSI'], |
| | | typeValue: 'VOL',//图形类型 |
| | | klinecharts: null,//K线图实例 |
| | | subTechnicalIndicatorTypes: [ |
| | | "MA", |
| | | "EMA", |
| | | "BOLL", |
| | | "VOL", |
| | | "MACD", |
| | | "KDJ", |
| | | "RSI", |
| | | ], |
| | | typeValue: "VOL", //图形类型 |
| | | klinecharts: null, //K线图实例 |
| | | chart: null, |
| | | // resolution: '1',//分辨率 |
| | | // lang: 'en', //语言 |
| | | chartLoading: true, //加载动画 |
| | | paneId: '', |
| | | paneId: "", |
| | | chartData: [], // 图表数据 |
| | | timer: null |
| | | } |
| | | timer: null, |
| | | grid: { |
| | | show: true, |
| | | horizontal: { |
| | | show: true, |
| | | size: 0.1, |
| | | color: "#f0f0f0", |
| | | style: "dashed", |
| | | dashedValue: [1, 2], |
| | | }, |
| | | vertical: { |
| | | show: true, |
| | | size: 0.1, |
| | | color: "#f0f0f0", |
| | | style: "dashed", |
| | | dashedValue: [1, 2], |
| | | }, |
| | | }, |
| | | }; |
| | | }, |
| | | computed: { |
| | | timeList() { |
| | | return [ |
| | | { id: '1min', time: '1min', text: this.$t('分时'), ts: 1 * 60 * 1000 }, |
| | | { id: '1mins', time: '1min', text: '1' + this.$t('分'), ts: 1 * 60 * 1000 }, |
| | | { id: '5min', time: '5min', text: '5' + this.$t('分'), ts: 5 * 60 * 1000 }, |
| | | { id: '15min', time: '15min', text: '15' + this.$t('分'), ts: 15 * 60 * 1000 }, |
| | | { id: '30min', time: '30min', text: '30' + this.$t('分'), ts: 30 * 60 * 1000 }, |
| | | { id: '60min', time: '60min', text: '1' + this.$t('小时'), ts: 60 * 60 * 1000 }, |
| | | { id: '4hour', time: '4hour', text: '4' + this.$t('小时'), ts: 4 * 60 * 60 * 1000 }, |
| | | { id: '1day', time: '1day', text: '1' + this.$t('天'), ts: 24 * 60 * 60 * 1000 }, |
| | | { id: '1week', time: '1week', text: '1' + this.$t('周'), ts: 7 * 24 * 60 * 60 * 1000 }, |
| | | { id: '1mon', time: '1mon', text: '1' + this.$t('月'), ts: 30 * 24 * 60 * 60 * 1000 } |
| | | ]//时间列表 |
| | | } |
| | | { id: "1min", time: "1min", text: this.$t("分时"), ts: 1 * 60 * 1000 }, |
| | | { |
| | | id: "1mins", |
| | | time: "1min", |
| | | text: "1" + this.$t("分"), |
| | | ts: 1 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "5min", |
| | | time: "5min", |
| | | text: "5" + this.$t("分"), |
| | | ts: 5 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "15min", |
| | | time: "15min", |
| | | text: "15" + this.$t("分"), |
| | | ts: 15 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "30min", |
| | | time: "30min", |
| | | text: "30" + this.$t("分"), |
| | | ts: 30 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "60min", |
| | | time: "60min", |
| | | text: "1" + this.$t("小时"), |
| | | ts: 60 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "4hour", |
| | | time: "4hour", |
| | | text: "4" + this.$t("小时"), |
| | | ts: 4 * 60 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "1day", |
| | | time: "1day", |
| | | text: "1" + this.$t("天"), |
| | | ts: 24 * 60 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "1week", |
| | | time: "1week", |
| | | text: "1" + this.$t("周"), |
| | | ts: 7 * 24 * 60 * 60 * 1000, |
| | | }, |
| | | { |
| | | id: "1mon", |
| | | time: "1mon", |
| | | text: "1" + this.$t("月"), |
| | | ts: 30 * 24 * 60 * 60 * 1000, |
| | | }, |
| | | ]; //时间列表 |
| | | }, |
| | | }, |
| | | components: { |
| | | [Loading.name]: Loading |
| | | [Loading.name]: Loading, |
| | | }, |
| | | props: { |
| | | symbol: { |
| | | type: String, |
| | | default: '' |
| | | default: "", |
| | | }, |
| | | updateKey: { |
| | | type: Number, |
| | | default: 0 |
| | | default: 0, |
| | | }, |
| | | updateData: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | return {}; |
| | | }, |
| | | }, |
| | | showBottom: { |
| | | type: Boolean, |
| | | default: true |
| | | default: true, |
| | | }, |
| | | isChangeLine: { |
| | | type: Boolean, |
| | | default: false |
| | | default: false, |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.initData() |
| | | this.initData(); |
| | | }, |
| | | beforeDestroy() { |
| | | this.clearTimer() |
| | | dispose('kline') |
| | | this.clearTimer(); |
| | | dispose("kline"); |
| | | }, |
| | | watch: { |
| | | isChangeLine(val) { |
| | | this.clearTimer() |
| | | this.fetchData() |
| | | this.clearTimer(); |
| | | this.fetchData(); |
| | | }, |
| | | updateKey() { // 更新charts |
| | | const dataList = chart.getDataList() |
| | | const lastData = dataList[dataList.length - 1] |
| | | const nowData = this.updateData |
| | | const timeValue = this.timeValue |
| | | updateKey() { |
| | | // 更新charts |
| | | const dataList = chart.getDataList(); |
| | | const lastData = dataList[dataList.length - 1]; |
| | | const nowData = this.updateData; |
| | | const timeValue = this.timeValue; |
| | | const newData = { |
| | | close: nowData.close / 1, |
| | | current_time: lastData.current_time, |
| | | high: lastData.high > nowData.close / 1 ? lastData.high : (nowData.close / 1), |
| | | high: |
| | | lastData.high > nowData.close / 1 ? lastData.high : nowData.close / 1, |
| | | // high: lastData.high, |
| | | line: timeValue.id, |
| | | low: lastData.low < nowData.close / 1 ? lastData.low : (nowData.close / 1), |
| | | low: |
| | | lastData.low < nowData.close / 1 ? lastData.low : nowData.close / 1, |
| | | // low: lastData.low, |
| | | open: lastData.open, |
| | | symbol: lastData.symbol, |
| | | ts: lastData.ts, // |
| | | timestamp: (nowData.ts - lastData.ts) < timeValue.ts ? lastData.ts : (lastData.ts + timeValue.ts), |
| | | volume: lastData.volume / 1 |
| | | } |
| | | timestamp: |
| | | nowData.ts - lastData.ts < timeValue.ts |
| | | ? lastData.ts |
| | | : lastData.ts + timeValue.ts, |
| | | volume: lastData.volume / 1, |
| | | }; |
| | | this.$nextTick(() => { |
| | | this.setChartType() |
| | | chart.updateData(newData) |
| | | }) |
| | | } |
| | | this.setChartType(); |
| | | chart.updateData(newData); |
| | | }); |
| | | }, |
| | | }, |
| | | methods: { |
| | | initData() { |
| | | this.timeValue = this.timeList[0] |
| | | chart = init('kline', config); |
| | | chart.setOffsetRightSpace(25) |
| | | chart.setDataSpace(10) |
| | | chart.setPriceVolumePrecision(4, 2) |
| | | chart.createTechnicalIndicator('MA', false, { id: 'candle_pane' }); |
| | | this.paneId = chart.createTechnicalIndicator('VOL'); |
| | | this.fetchData() |
| | | this.timeValue = this.timeList[0]; |
| | | chart = init("kline", config); |
| | | chart.setOffsetRightSpace(25); |
| | | chart.setDataSpace(10); |
| | | chart.setPriceVolumePrecision(4, 2); |
| | | chart.createTechnicalIndicator("MA", false, { id: "candle_pane" }); |
| | | chart.getStyleOptions().grid = this.grid; |
| | | chart.setStyleOptions({ |
| | | grid: this.grid, |
| | | // candle: { |
| | | // upColor: "#FF0000", |
| | | // downColor: "#00FF00", |
| | | // borderUpColor: "#FF0000", |
| | | // borderDownColor: "#00FF00", |
| | | // wickUpColor: "#FF0000", |
| | | // wickDownColor: "#00FF00", |
| | | // }, |
| | | }); |
| | | this.paneId = chart.createTechnicalIndicator("VOL"); |
| | | this.fetchData(); |
| | | }, |
| | | fetchData(time) { // 获取数据 |
| | | this.chartLoading = true |
| | | fetchData(time) { |
| | | // 获取数据 |
| | | this.chartLoading = true; |
| | | this.timer = setInterval(() => { |
| | | _getKline(this.symbol, this.timeValue.time || time).then(data => { |
| | | this.chartLoading = false |
| | | data.map(item => { |
| | | item.timestamp = item.ts |
| | | }) |
| | | _getKline(this.symbol, this.timeValue.time || time).then((data) => { |
| | | this.chartLoading = false; |
| | | data.map((item) => { |
| | | item.timestamp = item.ts; |
| | | }); |
| | | //科学计数法时转成字符串 |
| | | let str = data[0] ? scientificNotationToString(data[data.length - 1].close.toString()) : '' |
| | | let length = 2 |
| | | if (str.indexOf('.') != -1) { |
| | | length = str.split('.')[1].length |
| | | let str = data[0] |
| | | ? scientificNotationToString(data[data.length - 1].close.toString()) |
| | | : ""; |
| | | let length = 2; |
| | | if (str.indexOf(".") != -1) { |
| | | length = str.split(".")[1].length; |
| | | } |
| | | //let length = data[0] ? data[0].close.toString().split('.')[1].length : 4 |
| | | chart.setPriceVolumePrecision(length, 2) |
| | | this.setChartType() |
| | | chart.setPriceVolumePrecision(length, 2); |
| | | this.setChartType(); |
| | | chart.applyNewData(data); |
| | | this.$emit('updataLine', false) |
| | | }) |
| | | this.$emit("updataLine", false); |
| | | }); |
| | | }, 1000); |
| | | }, |
| | | setChartType() { |
| | | let type = 'area' |
| | | if (this.timeValue.id === '1min') { |
| | | type = 'area' |
| | | let type = "area"; |
| | | if (this.timeValue.id === "1min") { |
| | | type = "area"; |
| | | } else { |
| | | type = 'candle_solid' |
| | | type = "candle_solid"; |
| | | } |
| | | chart.setStyleOptions({ |
| | | candle: { |
| | | type |
| | | } |
| | | }) |
| | | type, |
| | | }, |
| | | }); |
| | | }, |
| | | choiceTime(value) { // 选择周期 |
| | | this.timeValue = value |
| | | this.clearTimer() |
| | | this.fetchData() |
| | | choiceTime(value) { |
| | | // 选择周期 |
| | | this.timeValue = value; |
| | | this.clearTimer(); |
| | | this.fetchData(); |
| | | }, |
| | | choiceType(type) { // 选择副线 |
| | | this.typeValue = type |
| | | chart.createTechnicalIndicator(type, false, { id: this.paneId }) |
| | | choiceType(type) { |
| | | // 选择副线 |
| | | this.typeValue = type; |
| | | chart.createTechnicalIndicator(type, false, { id: this.paneId }); |
| | | }, |
| | | clearTimer() { |
| | | clearInterval(this.timer) |
| | | this.timer = null |
| | | clearInterval(this.timer); |
| | | this.timer = null; |
| | | }, |
| | | }, |
| | | deactivated() { |
| | | this.clearTimer() |
| | | } |
| | | } |
| | | this.clearTimer(); |
| | | }, |
| | | }; |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .textColor { |