addHeatmap.vue 10.5 KB
<template>
    <div class="addition-heatmap" @mousemove="mousemoveHandle" @mouseout="mouseoutHandle">
        <el-header height="70px">
            <span class="seq-title">{{ $t('echartsTitle.faceDistributionfaceTraffic') }}</span>
            <span class="more-option-wrapper" @click="showCollapse">
                <span class="more-option-text">{{ $t('asis.moreOp') }}</span>
                <i :class="moreOptVisible ? 'el-icon-arrow-down more-option-arrow' : 'el-icon-arrow-down more-option-arrow more-option-up'"></i>
            </span>
        </el-header>
        <!-- 条件检索 -->
        <div class="heatmap-condition" v-show="moreOptVisible">
            <ul class="condition-box">
                <li class="condition-item">
                    <span class="condition-item-text">{{ $t('asisTab.storeT') }}</span>
                    <div class="condition-item-option">
                        <el-select v-model="storeVal" :placeholder="$t('pholder.shopS')">
                            <!-- <el-option v-for="" :key=""></el-option>  -->
                        </el-select>
                    </div>
                </li>
                <li class="condition-item">
                    <span class="condition-item-text">{{ $t('asisTab.date') }}</span>
                    <div class="condition-item-option">
                        <el-date-picker v-model="timeVal" class="time-opt" :placeholder="$t('pholder.timeSelect')" :picker-options="pickerOptions1"></el-date-picker>
                    </div>
                </li>
                <li class="condition-item">
                    <el-button type="primary" class="primary-btn analysis-collapse-btn" size="samll" @click="confirmCondition">{{$t('button.confirm')}}</el-button>
                    <el-button class="reset-btn analysis-collapse-btn" size="samll" @click="resetRefresh">{{$t('button.reset')}}</el-button>
                </li>
            </ul>
            <!-- <div class="test-opt-time">
                <span class="condition-item-text">日期: </span>
                <el-date-picker v-model="timeVal" class="time-opt" placeholder="请选择时间" :picker-options="pickerOptions1"></el-date-picker>
            </div> -->
        </div>
        <!-- 热力图 -->
        <div class="heatmap-box">
            <div class="heatmap-wrapper">
                <div class="heatmap-content">
                    <img src="./img/heatmap_test.jpg" width="100%" height="100%" />
                </div> 
                <div class="tooltip"></div>
                <div class="legend-wrapper">
                    <span id="min"></span>
                    <span id="max"></span>
                    <img src="./img/gradient.png" id="gradient" />
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            moreOptVisible: false,
            timeVal: '',
            pickerOptions1: {
                disabledDate(time) {
                    return time.getTime() > Date.now();
                },
            },
            storeVal: '',
            storeOpt: [],
            legendCanvas: '',
            gradientCfg: {},
            gradientImg: '',
            legendCtx: '',
            heatmapInstance: {}
        }
    },
    mounted() {
        this.initHeatmap();
    },
    methods: {
        showCollapse() {
            // 获取上面元素的高度
            let headerH = '', titleH = '', collapseH = '', mt = '';
                headerH = this.getStyleFn('.el-header', 'height');
                titleH = this.getStyleFn('.analysis-wrapper .el-header', 'height');
            if(this.moreOptVisible) {
                this.moreOptVisible = false;
                $('.heatmap-box').animate({ marginTop: mt });
                mt = headerH + titleH + 8 + 'px';
            } else {
                this.moreOptVisible = true;
                setTimeout(() => {
                    collapseH = this.getStyleFn('.analysis-option-wrapper', 'height');
                    mt = headerH + titleH + collapseH + 8 + 'px';
                    $('.heatmap-box').animate({ marginTop: mt });
                }, 100);
            }
        },
        initHeatmap() {
            this.legendCanvas = document.createElement('canvas');
            this.legendCanvas.width = 100;
            this.legendCanvas.height = 10;
            // this.min = document.querySelector('#min');
            // this.max = document.querySelector('#max');
            this.gradientImg = document.querySelector('#gradient');
            this.legendCtx = this.legendCanvas.getContext('2d');
            this.heatmapInstance = h337.create({
                container: document.querySelector('.heatmap-content'),
                onExtremaChange: (data) => {
                    this.updateLegend(data);
                }
            });
            let data = this.mockData();
            this.heatmapInstance.setData(data);
        },
        updateLegend(data) {
            let min = document.querySelector('#min');
            let max = document.querySelector('#max');
            min.innerHTML = data.min;
            max.innerHTML = data.max;
            if (data.gradient != this.gradientCfg) {
                this.gradientCfg = data.gradient;
                let gradient = this.legendCtx.createLinearGradient(0, 0, 100, 1);
                for (var key in this.gradientCfg) {
                    gradient.addColorStop(key, this.gradientCfg[key]);
                }
                this.legendCtx.fillStyle = gradient;
                this.legendCtx.fillRect(0, 0, 100, 10);
                this.gradientImg.src = this.legendCanvas.toDataURL();
            }
        },
        mockData() {
            let points = [];
            let max = 0;
            let min = 1234;
            let width = 840;
            let height = 400;
            let len = 10;
            while (len--) {
                let val = Math.floor(Math.random() * 1234);
                max = Math.max(max, val);
                min = Math.min(min, val);
                let point = {
                    x: Math.floor(Math.random() * width),
                    y: Math.floor(Math.random() * height),
                    value: val
                };
                points.push(point);
            }
            return {
                max: max,
                min: min,
                data: points
            }
        },
        updateTooltip(x, y, value) {
            let ele_tooltip = document.querySelector('.tooltip');
            var transl = 'translate(' + (x + 15) + 'px, ' + (y + 15) + 'px)';
            ele_tooltip.style.webkitTransform = transl;
            ele_tooltip.innerHTML = '客流量: ' + value + '人次';
        },
        mousemoveHandle(ev) {
            let ele_tooltip = document.querySelector('.tooltip');
            let x = ev.layerX;
            let y = ev.layerY;
            let value = this.heatmapInstance.getValueAt({
                x: x,
                y: y
            });
            if(value) {
                ele_tooltip.style.display = 'block';
                this.updateTooltip(x, y, value);
            } else {
                ele_tooltip.style.display = 'none';
            }
        },
        mouseoutHandle() {
            let ele_tooltip = document.querySelector('.tooltip');
            ele_tooltip.style.display = 'none';
        },
        confirmCondition() {
            //
        },
        resetRefresh() {
            //
        }
    }
}
</script>

<style scoped>
    /* @import url(../common/css/fixed_layout.css); */
    .addition-heatmap {
        width: calc(100% - 200px);
        margin-top: .82rem;
        margin-left: 200px;
    }

    .el-header {
        background-color: #fff;
        color: #555;
        text-align: center;
        height: .7rem !important;
        line-height: .7rem;
        font-size: 0.28rem;
        padding-right: 0.85rem;
        padding-left: 1.2rem;
        margin-left: 0;
        border-bottom: 1px solid rgba(177, 177, 177, .2);
    }

    .seq-title {
        color: #555;
    }

    .more-option-wrapper {
        float: right;
        font-size: 0.12rem;
        color: #666;
        cursor: pointer;
        margin-top: 0.14rem;
    }

    .more-option-arrow {
        transition: transform .3s;
    }

    .more-option-up {
        transform: rotate(-180deg);
    }

    /* 条件 */
    .heatmap-condition {
        margin-top: .7rem;
        width: 100%;
        padding: 0.24rem 0 0.28rem 0.72rem;
        background: #fff;
        position: fixed;
        z-index: 2;
        box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .1);
    }

    .condition-box:after,
    .condition-box:before {
        content: "";
        display: table;
    }

    .condition-box:after {
        clear: both;
    }

    .condition-item {
        float: left;
        list-style: none;
        font-size: 0.14rem;
    }

    .condition-item:not(:first-child) {
        margin-left: 1.24rem;
    }

    .condition-item-text {
        display: inline-block;
        font-size: 0.14rem;
        color: #666;
    }

    .condition-item-option {
        display: inline-block;
        font-size: 0.14rem;
        margin-left: 0.4rem;
    }

    .time-opt {
        height: 0.3rem;
        line-height: 0.3rem;
    }

    .analysis-collapse-btn {
        font-family: 微软雅黑, "Lantinghei SC", "Open Sans", Arial, "Hiragino Sans GB", "Microsoft YaHei", STHeiti, "WenQuanYi Micro Hei", SimSun, sans-serif;
        font-size: 0.14rem;
        padding: 0.08rem 0.17rem;
        font-weight: normal;
    }

    .primary-btn {
        background: #0069FF;
        border: none;
    }

    .heatmap-box {
        padding: 12px 25px;
        /* background-color: #fff; */
        margin-top: .7rem;
    }

    .heatmap-wrapper {
        position: relative;
        padding: 15px;
        height: 700px;
        background: #fff;
    }

    .heatmap-content {
        position: relative;
        width: 100%;
        height: 100%;
    }

    .tooltip {
        position: absolute;
        left: 0;
        top: 0;
        background: #fff;
        color: #444;
        border-radius: 4px;
        text-align: left;
        font-size: 14px;
        padding: 15px;
        line-height: 18px;
        display: none;
    }

    .legend-wrapper {
        position: absolute;
        bottom: 20px;
        right: 20px;
        padding: 10px;
        background: #fff;
        line-height: 0;
    }

    #min {
        float: left;
        font-size: 14px;
        margin: 10px 0 0;
        padding: 0;
    }

    #max {
        float: right;
        font-size: 14px;
        margin: 10px 0 0;
        padding: 0;
    }

    #gradient {
        width: 100%;
    }
</style>