You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VEGA交互式柱状图实现Ctrl/Shift多选功能技术咨询

Vega 柱状图实现 Ctrl/Shift 多选功能

基于官方基础柱状图示例,以下是添加了 Ctrl/Shift 多选功能的完整代码,支持选中柱状条后进行差值、最大值、最小值、平均值等计算:

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "柱状图支持Ctrl/Shift多选,可查看选中数据的统计值",
  "width": 400,
  "height": 200,
  "padding": 5,

  "data": [
    {
      "name": "table",
      "values": [
        {"category": "A", "amount": 28},
        {"category": "B", "amount": 55},
        {"category": "C", "amount": 43},
        {"category": "D", "amount": 91},
        {"category": "E", "amount": 81},
        {"category": "F", "amount": 53},
        {"category": "G", "amount": 19},
        {"category": "H", "amount": 87}
      ]
    },
    {
      "name": "selectedStats",
      "source": "table",
      "transform": [
        {
          "filter": "indexof(selected, datum.category) !== -1"
        },
        {
          "aggregate": [
            {"op": "max", "field": "amount", "as": "maxAmount"},
            {"op": "min", "field": "amount", "as": "minAmount"},
            {"op": "mean", "field": "amount", "as": "avgAmount"},
            {"op": "count", "field": "category", "as": "count"}
          ]
        }
      ]
    }
  ],

  "signals": [
    {
      "name": "tooltip",
      "value": {},
      "on": [
        {"events": "rect:pointerover", "update": "datum"},
        {"events": "rect:pointerout",  "update": "{}"}
      ]
    },
    {
      "name": "selected",
      "value": [],
      "on": [
        // 普通点击:替换选中项
        {
          "events": {"type": "click", "source": "scope", "consume": true},
          "update": "!event.ctrlKey && !event.shiftKey ? [datum.category] : selected"
        },
        // Ctrl点击:切换当前项的选中状态
        {
          "events": {"type": "click", "source": "scope", "consume": true, "modifiers": "ctrl"},
          "update": "indexof(selected, datum.category) !== -1 ? remove(selected, datum.category) : concat(selected, [datum.category])"
        },
        // Shift点击:选中连续范围
        {
          "events": {"type": "click", "source": "scope", "consume": true, "modifiers": "shift"},
          "update": "lastClicked ? getRange(lastClicked, datum.category) : [datum.category]"
        }
      ]
    },
    {
      "name": "lastClicked",
      "value": "",
      "on": [
        {"events": {"type": "click", "source": "scope", "consume": true}, "update": "datum.category"}
      ]
    },
    {
      "name": "categoryOrder",
      "value": ["A", "B", "C", "D", "E", "F", "G", "H"]
    }
  ],

  "scales": [
    {
      "name": "xscale",
      "type": "band",
      "domain": {"data": "table", "field": "category"},
      "range": "width",
      "padding": 0.05,
      "round": true
    },
    {
      "name": "yscale",
      "domain": {"data": "table", "field": "amount"},
      "nice": true,
      "range": "height"
    }
  ],

  "axes": [
    { "orient": "bottom", "scale": "xscale" },
    { "orient": "left", "scale": "yscale" }
  ],

  "marks": [
    {
      "type": "rect",
      "from": {"data":"table"},
      "encode": {
        "enter": {
          "x": {"scale": "xscale", "field": "category"},
          "width": {"scale": "xscale", "band": 1},
          "y": {"scale": "yscale", "field": "amount"},
          "y2": {"scale": "yscale", "value": 0}
        },
        "update": {
          "fill": {"signal": "indexof(selected, datum.category) !== -1 ? '#e63946' : 'steelblue'"},
          "cursor": {"value": "pointer"}
        },
        "hover": {
          "fill": {"signal": "indexof(selected, datum.category) !== -1 ? '#d62828' : '#457b9d'"}
        }
      }
    },
    {
      "type": "text",
      "encode": {
        "enter": {
          "align": {"value": "center"},
          "baseline": {"value": "bottom"},
          "fill": {"value": "#333"}
        },
        "update": {
          "x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
          "y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
          "text": {"signal": "tooltip.amount"},
          "fillOpacity": [
            {"test": "datum === tooltip", "value": 0},
            {"value": 1}
          ]
        }
      }
    },
    // 显示选中数据的统计信息
    {
      "type": "text",
      "from": {"data": "selectedStats"},
      "encode": {
        "enter": {
          "x": {"value": 10},
          "y": {"value": 20},
          "fontSize": {"value": 12},
          "fill": {"value": "#222"}
        },
        "update": {
          "text": {"signal": "datum.count > 0 ? '选中' + datum.count + '项:最大值=' + datum.maxAmount + ',最小值=' + datum.minAmount + ',平均值=' + round(datum.avgAmount) : ''"}
        }
      }
    }
  ],

  "functions": [
    // 实现连续范围选中的辅助函数
    {
      "name": "getRange",
      "parameters": ["start", "end"],
      "body": "var order = categoryOrder; var startIdx = indexof(order, start); var endIdx = indexof(order, end); var minIdx = min(startIdx, endIdx); var maxIdx = max(startIdx, endIdx); return slice(order, minIdx, maxIdx + 1);"
    },
    // 移除数组元素的辅助函数
    {
      "name": "remove",
      "parameters": ["arr", "item"],
      "body": "var idx = indexof(arr, item); return idx !== -1 ? concat(slice(arr, 0, idx), slice(arr, idx + 1)) : arr;"
    }
  ]
}

关键功能说明

  • 普通点击:直接替换当前选中的柱状条,仅保留当前点击项
  • Ctrl+点击:切换单个柱状条的选中状态(已选中则取消,未选中则添加)
  • Shift+点击:选中从最后一次点击项到当前点击项的连续范围
  • 统计信息展示:自动计算并显示选中项的数量、最大值、最小值和平均值,可根据需求扩展差值等其他计算逻辑
  • 视觉反馈:选中的柱状条显示为红色,hover时颜色加深,与未选中的蓝色形成区分

内容的提问来源于stack exchange,提问作者s p

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:07:34