大屏echarts甘特图表

//父组件
<div class="lifecycle-content" >
     <Ganttchart />
</div>
.lifecycle-content {
    position: relative;
    width:100%;
    height: calc(100% - 40px);
}
.lifecycle-content > div {
    position: absolute;
    top: 0;
    bottom: 0;
}
//子组件
<template>
    <div ref="chartPanel" class="chart-container" />
</template>
<script setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts';
import { getLifecycle } from "/@/api/lifecycle";
const chartPanel = ref(null)

const getDate = () => {
    getLifecycle({ page: 1, row: 10, sceneId: '27113A942A7E4ABABBA16D4EDAAB0EAE' }).then((res) => {
        let data = res.data[0].productDTO.organismStatusList
        // 提取所需的字段lifeCycleTaskLists
        let totalLength = 0;
        for (let i = 0; i < data.length; i++) {
            totalLength += data[i].lifeCycleTaskLists.length;
        }
        console.log(totalLength);
        let currentTextValue = totalLength;
        let result = data.map(item => {
            return item.lifeCycleTaskLists.map(task => {
                let text = currentTextValue - 1;
                currentTextValue--;
                return [
                    text,
                    task.actualStartTime,
                    task.planEndedTime,
                    task.actualEndedTime,
                    task.taskName
                ];
            });
        });
        result = result.flat();
        rowData.flight.data = result;
        // 提取所需的字段
        let resulttitle = data.map(item => {
            return item.lifeCycleTaskLists.map(task => {
                return [
                    task.organismName,
                    task.taskName
                ];
            });
        });
        resulttitle = resulttitle.flat();
        rowData.parkingApron.data = resulttitle;
        console.log('------', rowData);
        initChart();
    }).catch((err) => {
        console.log(err);
    });
}
const HEIGHT_RATIO = 0.5;
const DIM_CATEGORY_INDEX = 0;
const DIM_TIME_ARRIVAL = 1;
const DIM_TIME_DEPARTURE = 2;
const ACTUAL_TIME_ARRIVAL = 3;
const _cartesianXBounds = [];
const _cartesianYBounds = [];

const rowData = {
    flight: {
        data: [
            // [11, '2024-5-1', '2024-5-16', '2024-5-17', '', '播种'],
            // [10, '2024-1-1', '2024-1-8', '2024-1-9', '播种'],
            // [9, '2024-1-1', '2024-1-5', '2024-1-9', '播种'],
            // [8, '2024-1-1', '2024-1-4', '2024-1-9', '播种'],
            // [7, '2024-1-1', '2024-1-3', '2024-1-9', '播种'],
            // [6, '2024-1-1', '2024-1-31', '2024-1-24', '铺地膜'],
            // [5, '2024-2-1', '2024-4-30', '2024-4-30', '铺滴灌带'],
            // [4, '2024-5-1', '2024-5-31', '2024-6-30', '起垄'],
            // [3, '2024-6-1', '2024-6-30', '2024-7-15', '施肥'],
            // [2, '2024-7-1', '2024-7-15', '2024-7-23', 'Go live'],
            // [1, '2024-7-16', '2024-7-31', '2024-8-31', 'Training'],
            // [0, '2024-8-1', '2024-8-31', '', 'Payment'],
        ],
        dimensions: ['Parking Apron Index', '开始时间', '结束时间', '实际结束时间'],
    },
    parkingApron: {
        dimensions: ['Name', 'Type'],
        data: [
            // ['发芽期', '播种'],
            // ['发芽期', '铺地膜'],
            // ['幼苗期', '铺滴灌带'],
            // ['幼苗期', '起垄'],
            // ['结果期', '施肥'],
            // ['Task06', 'Go live'],
            // ['Task07', 'Training'],
            // ['Task08', 'Payment'],
            // ['Task9', 'Payment'],
            // ['Task10', 'Payment'],
            // ['Task11', 'Payment'],
            // ['Task12', 'Payment'],
        ],
    },
}

const initChart = () => {
    const myChart = echarts.init(chartPanel.value, null, { width: 'auto', height: 'auto' });

    function clipRectByRect(params, rect) {
        return echarts.graphic.clipRectByRect(rect, {
            x: params.coordSys.x,
            y: params.coordSys.y,
            width: params.coordSys.width,
            height: params.coordSys.height,
        })
    }
    function renderGanttItem(params, api) {
        const categoryIndex = api.value(DIM_CATEGORY_INDEX);
        const timeStart = api.coord([api.value(DIM_TIME_ARRIVAL), categoryIndex]);
        const timeEnd = api.coord([api.value(DIM_TIME_DEPARTURE), categoryIndex]);
        const actualTimeArrival = api.coord([api.value(ACTUAL_TIME_ARRIVAL), categoryIndex]);
        const { coordSys } = params;
        _cartesianXBounds[0] = coordSys.x;
        _cartesianXBounds[1] = coordSys.x + coordSys.width;
        _cartesianYBounds[0] = coordSys.y;
        _cartesianYBounds[1] = coordSys.y + coordSys.height;
        const barLength1 = timeEnd[0] - timeStart[0];
        const barLength2 = timeEnd[0] - actualTimeArrival[0];
        const barLength3 = actualTimeArrival[0] - timeEnd[0];

        const barHeight = api.size([0, 1])[1] * HEIGHT_RATIO;

        const rectNormal = clipRectByRect(params, {
            x: timeStart[0],
            y: timeStart[1] - barHeight,
            width: barLength1,
            height: barHeight,
        });
        const rectBefore = clipRectByRect(params, {
            x: actualTimeArrival[0],
            y: actualTimeArrival[1] - barHeight,
            width: barLength2,
            height: barHeight,
        });
        const rectAfter = clipRectByRect(params, {
            x: timeEnd[0],
            y: timeEnd[1] - barHeight,
            width: barLength3,
            height: barHeight,
        });
        return {
            type: 'group',
            children: [
                {
                    type: 'rect',
                    ignore: !rectNormal,
                    shape: rectNormal,
                    style: api.style({ fill: '#fac758' }), // 黄色区域-开始时间到结束时间
                },
                {
                    type: 'rect',
                    ignore: !rectBefore,
                    shape: rectBefore,
                    style: api.style({ fill: '#3ba272' }), // 绿色区域 - 提前结束
                },
                {
                    type: 'rect',
                    ignore: !rectAfter,
                    shape: rectAfter,
                    style: api.style({ fill: '#ee6666' }), // 红色区域-延迟
                },
            ],
        };
    }
    function renderAxisLabelItem(params, api) {
        const y = api.coord([0, api.value(0)])[1];
        if (y < params.coordSys + 5) {
            return;
        }
        // eslint-disable-next-line consistent-return
        return {
            type: 'group',
            position: [0, y],
            children: [
                {
                    type: 'path', // task区域
                    shape: {
                        d: 'M0,0 L0,-20 L30,-20 C42,-20 38,-1 50,-1 L70,-1 L70,0 Z',
                        x: 0,
                        y: -20,
                        width: 80,
                        height: 20,
                        layout: 'cover',
                    },
                    style: {
                        fill: '#368c6c',

                    },
                },
                {
                    type: 'text', // task字体
                    style: {
                        x: 24,
                        y: -3,
                        size: 1,
                        text: api.value(1),
                        textVerticalAlign: 'bottom',
                        textAlign: 'center',
                        textFill: '#fff',
                    },
                },
                {
                    type: 'text', // 项目名称
                    style: {
                        x: 50,
                        y: -2,
                        textVerticalAlign: 'bottom',
                        textAlign: 'left',
                        text: api.value(2),
                        textFill: '#fff',  //--------------------------字体
                    },
                },
            ],
        };
    }

    function makeOption() {
        return {
            tooltip: {
                trigger: 'item',
                show: true,
                axisPointer: {
                    type: 'line',
                },
                formatter(params) {
                    if (params && params.length > 0) {
                        return '';
                    }
                    const { data, value } = params;
                    const end = value[2] ? new Date(value[2]).getTime() : 0;
                    const actual = value[3] ? new Date(value[3]).getTime() : 0;
                    let color = '#ddb30b';
                    if (actual - end > 0) {
                        color = '#ee6666';
                    } else if (actual - end < 0) {
                        color = '#3ba272';
                    }
                    const marker = `<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${color};"></span>`;
                    return `${data[4]} <br/>${marker}开始时间:${value[1]}<br/>${marker}结束时间:${value[2]}<br/>${marker}实际结束时间:${value[3]}`;
                },
            },
            animation: false,
            grid: {
                show: true,
                top: 50,
                bottom: 0,
                left: 110,
                right: 20,
                borderWidth: 0,
            },
            dataZoom: [
                {
                    type: 'slider',
                    xAxisIndex: 0,
                    filterMode: 'weakFilter',
                    height: 20,
                    bottom: 0,
                    start: 7,
                    end: 0,
                    handleIcon:
                        'path://M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
                    handleSize: '70%',
                    showDetail: false,
                },
                {
                    type: 'inside',
                    id: 'insideX',
                    xAxisIndex: 0,
                    filterMode: 'weakFilter',
                    start: 0,
                    end: 100,
                    zoomOnMouseWheel: false,
                    moveOnMouseMove: true,
                },
                {
                    type: 'slider',
                    yAxisIndex: 0,
                    zoomLock: true,
                    width: 10,
                    right: 10,
                    top: 40,
                    bottom: 10,
                    start: 70,
                    end: 100,
                    handleSize: 0,
                    showDetail: false,
                },
                {
                    type: 'inside',
                    id: 'insideY',
                    yAxisIndex: 0,
                    start: 95,
                    end: 100,
                    zoomOnMouseWheel: false,
                    moveOnMouseMove: true,
                    moveOnMouseWheel: true,
                },
            ],
            xAxis: {
                type: 'time',
                position: 'top',
                splitLine: {
                    alignWithLabel: true,
                    show: true,
                    lineStyle: {
                        color: ['#E9EDFF'],
                    },
                },
                axisLine: {
                    show: false,
                },
                axisTick: {
                    show: false,
                    lineStyle: {
                        color: '#929ABA',
                    },
                },
                axisLabel: {
                    color: '#FFFFFF',
                    inside: false,
                    align: 'center',
                    formatter: (param) => {
                        const formatDate = new Date(param);
                        return `${formatDate.getFullYear()}-${formatDate.getMonth() + 1
                            }-${formatDate.getDate()}`;
                    },
                },
                axisPointer: {
                    show: true,
                    label: {
                        backgroundColor: '#004f53',
                        margin: -20,
                    },
                    lineStyle: {
                        color: '#9fbfcd',
                        type: 'solid',
                        width: 1.5,
                    },
                },
            },
            yAxis: {
                axisTick: { show: false },
                splitLine: { show: false },
                axisLine: { show: false },
                axisLabel: { show: false },
                min: 0,
                axisPointer: {
                    show: false,
                },
                max: rowData.parkingApron.data.length,
            },
            legend: {
                show: true,
                data: [ //---------------------------------
                    {
                        name: '提前完成',
                        itemStyle: { color: '#3ba272' },
                        textStyle: { color: '000' },
                    },
                    {
                        name: '逾期完成',
                        itemStyle: { color: '#ee6666' },
                        textStyle: { color: '000' },
                    },
                    {
                        name: '按时完成',
                        itemStyle: { color: '#fac758' },
                        textStyle: { color: '000' },
                    },
                ],
            },
            series: [
                {
                    id: 'flightData1',
                    type: 'custom',
                    name: '提前完成',
                    renderItem: renderGanttItem,
                    dimensions: rowData.flight.dimensions,
                    encode: {
                        x: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                        y: DIM_CATEGORY_INDEX,
                        tooltip: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                    },
                    data: rowData.flight.data,
                },
                {
                    id: 'flightData2',
                    type: 'custom',
                    name: '逾期完成',
                    renderItem: renderGanttItem,
                    dimensions: rowData.flight.dimensions,
                    encode: {
                        x: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                        y: DIM_CATEGORY_INDEX,
                        tooltip: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                    },
                    data: rowData.flight.data,
                },
                {
                    id: 'flightData3',
                    type: 'custom',
                    name: '按时完成',
                    renderItem: renderGanttItem,
                    dimensions: rowData.flight.dimensions,
                    encode: {
                        x: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                        y: DIM_CATEGORY_INDEX,
                        tooltip: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE, ACTUAL_TIME_ARRIVAL],
                    },
                    data: rowData.flight.data,
                },
                {
                    type: 'custom',
                    renderItem: renderAxisLabelItem,
                    dimensions: rowData.parkingApron.dimensions,
                    encode: {
                        x: -1,
                        y: 0,
                    },
                    data: rowData.parkingApron.data.map((item, index) => {
                        return [rowData.parkingApron.data.length - 1 - index].concat(item);
                    }),
                },
            ],
        };
    }

    const option = makeOption()
    myChart.setOption(option);
    window.addEventListener('resize', () => {
        myChart.resize();
    });
};

onMounted(() => {
    getDate()
});
</script>
<style scoped>
.chart-container {
    width:100%;
    overflow-y: scroll;
    scrollbar-width: none;
}
</style>

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回答: echarts甘特图可以通过Echarts库来实现,你可以在Echarts官网的实例中找到官方示例图以及其他贡献者发布的图。控制图的js代码基本结构如下: ```javascript // 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); // 指定图的配置项和数据 var option = { title: { text: 'ECharts 入门示例' }, tooltip: {}, legend: { data:['销量'] }, xAxis: { data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] }; // 使用刚指定的配置项和数据显示图 myChart.setOption(option); ``` 根据你提供的图效果,甘特图的横坐标刻度值为时间,纵坐标为“方案”、“纲要”、“成果”三个项目阶段类目。每个阶段类目中包含了按时完成(蓝色柱状图)和超时完成(红色柱状图)两种系列的数据。此外,还有垂直于x时间坐标轴的“计划开始时间”和“有效期”两条时间标线。结合官网文档和示例,以上是初步的结论。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用 Echarts 实现项目进度甘特图](https://blog.csdn.net/qq_33404903/article/details/84341339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值