可視化的交互語法

> 本文做者:AntV 架構師-蕭慶javascript

簡介

Antv 過去 5 年中,在不少可視化領域進行了探索,在統計圖表、可視分析、關係圖、地理可視化等可視化場景中都面臨如何把數據轉換成圖形(可視化編碼)的問題,數據一旦以圖形的方式呈現給用戶,用戶則須要在上面進行交互,查看數據細節從不一樣的層面對數據進行探查,以一句可視化領域常說的話來總結:「Overview first, zoom and filter, then details-on-demand"。 image.png > 《Visuallization Analysis&Design》是這個領域的一本很是經典的書籍,感興趣的不能錯過。java

G2(統計圖表) 、F2(移動端圖表)、L7(地理可視化)和 G6(關係可視化) 都在 Overview first 上有了很大的收穫,經過可視化編碼咱們已經探索了全部常見圖表如何從數據轉換成圖形。從而在 G二、F2 上造成圖形語法,在 L7 上使用地理符號學,在 G6上也支持數據映射到節點和邊的狀態,可是接下來的交互咱們尚未造成統一的理論依據,各自爲政。今天咱們在 G2 4.0 上根據過去的經驗和教訓總結出一套交互語法,初步驗證了完備性、易用性和實現交互的效率,咱們將會推廣到其餘產品上。git

交互回顧

以 G2 爲例,咱們在交互方面的探索主要有三個階段:github

  • 內置交互:能夠容許的交互都寫在代碼內部,同渲染、數據更新流程耦合
  • 可註冊交互:每一個交互一個名稱,能夠增長配置項用以控制觸發和反饋
  • 交互語法:將交互分爲多個階段,每一個階段分爲觸發和反饋,經過實現常見的反饋,來搭配觸發和反饋組合出一套新的交互。

交互內置

圖表的交互內置是一種直覺的實現方式,在通用圖表的開發過程當中,咱們能夠枚舉每種圖表支持的交互:瀏覽器

  • 全部圖表都支持 tooltip
  • 圖例可以進行數據過濾
  • 散點圖可使用矩形框框選,折線圖能夠框選 x 軸
  • 餅圖點擊能夠沿着圓心方向向外移動

可是一旦圖表庫同產品進行結合事情就沒那麼簡單,不少交互同圖表相關,可是又與產品的設計相關:框選、過濾、排序和標註等交互須要在不一樣的產品中有不一樣的觸發形式,而交互一旦內置,用戶很難改變交互的觸發方式和結果。架構

一旦用戶面臨交互的改造,咱們的答疑成本會激增,做爲圖表的開發者也很難改變交互的形態只能在上面增長配置項,打上一個個的補丁。框架

可註冊交互

出於交互能夠擴展,用戶能夠自由定製交互的目的,咱們在 G2 v3.四、F2 v3.三、G6 v2.1 版本上增長能夠註冊的交互,交互再也不同渲染和圖表的聲明週期進行耦合,依然以 G2 爲例:ssh

股票指數走勢探索 brush結合dataset
散點圖縮放交互 brush過濾圖形

其核心思想是:ide

  • 開放足夠多的事件
  • 使用名稱來表明一個交互,每種交互支持必定的配置項,使用時僅需一句代碼
chart.interaction('brush');

這種方案對於擴展性和用戶直接使用已經寫好的交互有比較好的支持,可是來定製交互的用戶須要深刻理解各個產品的內部細節,例如:框選了畫布,有哪些圖形會被框選,圖形對應的數據有哪些,如何進行過濾。函數

最終的結果是: 這套註冊交互的機制,主要仍是圖表庫(可視化工具)的開發者在使用,不少細節也實現的不夠好 

更進一步

前面兩種交互的實現方式有各類各樣的問題,所以咱們在尋找一種易於使用、易於擴展、易於理解的交互模式,由 G2 的圖形語法咱們想到了可否創造一套完備的交互語法。

交互語法

圖形語法的提示

如何在不影響現有圖表聲明週期(渲染、更新)的前提下,用戶能夠自由搭配交互,這看似是個無解的問題,咱們回到 G2 的起點 《The Grammar of Graphics》 ,Leland Wilkinson 將數據轉換爲圖形的過程拆解爲:

  • 度量:數據各個字段的特徵,如何將數據映射到 0-1 空間
  • 視覺通道:數據如何用可視化的形式來展現
  • 統計函數:彙總統計、迴歸、密度計算、連接等數據計算
  • 座標系:0-1 的數據如何映射到位置上
  • 幾何標記:抽象全部圖表類型,總結出7種抽象的幾何類型

image.png image.png<br>image.pngimage.png

交互語法的理論依據

回到可視化的交互方面,並無一套成熟的理論,可以提供出足夠的抽象,將現有的交互總結到一套框架中。咱們在 唐納德·A·諾曼 的 《設計心理學》中找到依據,他將交互過程劃分爲不一樣的階段: image.png<br>同時設計心理學中有 5 個核心的概念:

  • 示能:示能指的是物品與人之間的關係,物品的特性與決定物品預設用途的主體的能力之間的關係。
  • 意符:意符是一種提示,告訴用戶能夠採起什麼行爲,以及應該怎麼操做。
  • 映射:映射表示兩組事物要素之間的關係,一般用在控制與顯示的設計上。
  • 反饋:交互必須有反饋,告訴用戶交互正在執行,同時反饋一樣是交互的結果。
  • 概念模型:概念模型是高度簡化的說明,告訴用戶產品如何工做。讓用戶可以充分的理解交互的整個過程。

可視化的交互語法

綜合前面圖形語法和設計心理學中的理論依據,咱們對可視化的交互進行分析,總結出交互的目的,同時將可視化交互過程劃分爲多個交互環節,每一個過程分別有觸發和反饋。 <a name="KSxPk"></a>

交互目的

交互的目的也就是用戶使用交互的意圖,交互意圖是否可以知足,是交互設計的根本出發點。在可視化的交互中,用戶須要使用交互來完成:

  • 數據定義,肯定哪些數據展現,對數據進行操做、加工、探索<br>
  • 視圖操做,在不一樣的視圖上操做展現的數據,能夠在視圖上對數據進行選中、導航、調整數據的展現方式等<br>
  • 交互記錄,記錄交互的軌跡,能夠進行交互過程的展現

交互的目的決定: 用戶從哪裏開始交互,最終的交互結果是什麼 <br>對交互目的的詳細說明,參看 交互概述

交互過程

咱們將交互聚焦於可視化的場景時,整理了常見的交互後,發現這些交互都有一致的過程,咱們能夠將一個交互分解成多個交互環節:

  • 示能:表示交互能夠進行
  • 開始:交互開始
  • 持續:交互持續
  • 結束:交互結束
  • 回滾:取消交互,恢復到原始狀態

大多數的交互僅使用上面的部分過程,可是也有些交互須要全部的過程,咱們以一個框選高亮爲示例: highlight.gif

  1. 示能:
  • 觸發對象:畫布
  • 觸發事件:移動進畫布繪圖區域、移出畫布繪圖區域
  • 反饋:鼠標形狀變成十字、離開時鼠標形狀恢復
  1. 開始:
  • 觸發對象:畫布
  • 觸發事件:按下鼠標,並滑動鼠標
  • 反饋:出現 mask
  1. 持續 1
  • 觸發對象:畫布
  • 觸發事件:持續滑動鼠標
  • 反饋:mask 隨着鼠標變化
  1. 持續 2
  • 觸發對象:mask
  • 觸發事件:mask 的大小變化
  • 反饋:被 mask 遮擋的圖形高亮
  1. 結束:
  • 觸發對象:畫布
  • 觸發事件:鼠標擡起
  • 反饋:mask 依然顯示,遮擋的圖形繼續高亮
  1. 回滾:
  • 觸發對象:畫布
  • 觸發事件:鼠標雙擊
  • 反饋:mask 隱藏,選中效果取消

注意:這個交互當前的實現比較簡單,沒有考慮拖拽 mask、異常操做等,其最完整的形式咱們會在後文中給出,證實交互語法的完備性。

觸發和反饋

從上面列舉的框選過濾的示例中,咱們能夠看到一個交互過程當中各個環節都須要觸發對象、觸發事件和反饋,咱們簡單的將一個環節分爲:

  • 觸發:觸發的對象和觸發事件
  • 反饋:交互的影響是是什麼

咱們能夠看到交互的目的、概念模型貫穿整個過程,用戶須要理解哪些對象能夠進行交互,一個交互有哪些環節,每一個環節是否必要,是否清晰,交互的最終結果是否符合用戶的目標。

交互語法的實現

理論距離實現由很大的距離,在可視化的過程當中實現交互語法,須要綜合考慮交互目的、交互過程、觸發和反饋。咱們依然以 G2 爲示例,講解交互語法從設計到實現的整個過程。經過上面的討論咱們能夠抽象出交互的概念模型:

  • 一個圖表支持多個交互
  • 一個交互有多個交互環節
  • 每一個交互環節能夠有多個觸發和反饋
  • 一個觸發有觸發的對象和觸發的事件
  • 一個反饋也有反饋的對象和行爲

結構圖

經過上面的概念模型咱們能夠得出交互的結構圖: <a name="hZdIm"></a>

交互和交互環節

一個交互有多個交互環節,交互環節之間有順序關係和並行關係:

  • 只有一個交互開始(start) 才能結束(end)
  • 只有一個交互開始才能持續(processing)
  • 只有一個交互結束 (end) 才能回滾 (rollback)

image.png<br>咱們對交互的過程進行命名:

  • showEnable: 表示交互能夠執行
  • start: 交互觸發
  • processing: 交互持續
  • end: 交互結束
  • rollback:交互回滾

交互觸發 Trigger

一個交互環節能夠有多個觸發和反饋,每一個觸發分爲:

  • 觸發對象
  • 觸發事件

觸發對象和元素命名系統

咱們對 G2 全部能夠觸發交互的元素,都進行梳理而且命名:

  • 圖表元素:chart(圖表)、view(視圖)、geometry(幾何標記表明圖表類型)、element(數據對應的圖形)、component(組件)
  • 圖表元素的包含部分和別名:
    • plot(繪圖區域)
    • element 的在不一樣 geometry 下的名稱:point, interval, area 等
    • 組件的內部圖形:axis-label(座標軸文本)、 legend-item(圖例項)、annotation-line(輔助線) 等

觸發事件

能夠觸發的事件有瀏覽器支持的全部事件:

  • click, mousedown, mouseup, mouseenter, mouseleave 等事件
  • drag, dragstart, dragend, dragenter, dragover, dragleave 等拖拽事件
  • touch 等移動端事件
  • 組件和圖表的自定事件,如:圖例的 valuechange ,chart 的 afterrender 等事件

觸發對象和觸發的事件能夠組合使用,例如 'axis-lable:mouseenter'

交互反饋

每一個交互都須要反饋,以表示交互正在進行,同時最終的反饋也就是用戶操做的目的。咱們將交互的反饋命名爲 Action,反饋也分爲:

  • 反饋的對象
  • 反饋的行爲

反饋的對象

因爲反饋要表示交互的能夠進行、已經進行、持續和結束,咱們總結全部的交互反饋的對象,這些交互對象能夠是:

  • 數據源
  • 鼠標形狀
  • 圖表的圖形
  • 圖表的組件
  • 圖表的容器 Chart 和 View
  • 輔助的圖形元素,遮罩層 Mask、圖形的委託對象(拖拽)、操做按鈕

brush-3.gif

反饋的行爲

反饋的行爲同反饋對象相關,就是每一個反饋對象能夠支持的響應,例如:

  • 鼠標能夠支持:十字(crosshair)、指針(pointer)、默認(default)以及文本(text)等各類形狀,每一個形狀的轉換就是一個反饋的行爲。
  • 數據源操做: 過濾(filter),增刪改(add, update, remove) 等
  • 圖表容器的變化:畫布大小變化、視圖的位置變化
  • 圖表組件的變化: 高亮(highlight)、選中(selected)、激活(active)、 勾選(checked) 等狀態變化;組件位置的變化等

反饋對象和行爲的組合

反饋對象和行爲也能夠在交互,進行組合,可是因爲一個反饋的對象能夠有很是多的行爲,而共同的行爲有須要多個方法來實現一個反饋行爲能夠有多個方法,例如圖形的高亮(highlight)包括:

  • 高亮(highlight) ,設置元素高亮
  • 恢復(reset) , 取消元素的高亮
  • 清除(clear), 取消全部元素的高亮

咱們將上面的 Action 命名爲 element-highlight ,一個反饋使用反饋行爲和方法進行組合 'element-active:highlight', 'element-active:reset',<br>highlight1.gif

同觸發的組合

由此咱們就能夠經過觸發和反饋搭配出一個交互的多個環節:<br>環節一:

trigger: 'element:mouseenter'
action: 'element-highlight:highlight'

環節二:

trigger: 'element:mouseleave'
action: 'element-highlight:reset'

進行組合,就完成了圖形 highlight 的交互:

{
	start: {
    trigger: 'element:mouseenter'
		action: 'element-highlight:highlight'
  },
  end: {
  	trigger: 'element:mouseleave'
		action: 'element-highlight:reset'
  }
}

組裝交互

經過上面的簡單的示例咱們能夠看到交互能夠經過定義交互環節,並在交互環節中配置觸發和反饋來實現,回到咱們一開始的框選高亮爲示例,來看一下如何組合出這個交互:

  1. 示能:
  2. 鼠標進入繪圖區域時,變成十字
  3. 鼠標離開繪圖區域時,變成默認形狀
showEnable: [
	{ trigger: 'plot:mouseenter', action: 'cursor:crosshair' },
  { trigger: 'plot:mouseleave', action: 'cursor:default' },
]
  1. 開始
  2. 鼠標在繪圖區域按下時,開始顯示矩形的遮罩層(rect-mask),並顯示
start: [{
  trigger: 'plot:mousedown',
  action: ['rect-mask:start', 'rect-mask:show'],
}]
  1. 持續
  2. 鼠標持續移動,矩形的遮罩(rect-mask) 形狀跟隨鼠標變化
  3. 隨着矩形遮罩(rect-mask)被遮罩的圖形高亮
processing: [
  {trigger: 'plot:mousemove', action:'rect-mask:resize'},
  {trigger: 'rect-mask:change', action: 'element-highlight:highlight'}
]
  1. 結束
  2. 鼠標擡起時,矩形的遮罩(rect-mask) 結束變化
end: [
  {trigger: 'plot:mouseup', action: 'rect-mask:end'}
]
  1. 回滾
  2. 雙擊畫布,矩形的遮罩(rect-mask) 消失,高亮效果消失
rollback: [
  {trigger: 'dblclick', action: ['rect-mask:hide', 'element-highlight:clear']}
]

highlight.gif

更加完善

這個交互就完成了,可是咱們在操做中發現,框選後還要可以拖拽遮罩(rect-mask),拖拽到畫布外面時須要異常處理等,咱們能夠繼續完善各個環節,最終效果以下:<br>drag-mask1.gif<br>最終的交互語法也就完成了:

{
  showEnable: [
    { trigger: 'plot:mouseenter', action: 'cursor:crosshair' },
    { trigger: 'mask:mouseenter', action: 'cursor:move' },
    { trigger: 'plot:mouseleave', action: 'cursor:default' },
    { trigger: 'mask:mouseleave', action: 'cursor:crosshair' },
  ],
  start: [
    {
      trigger: 'plot:mousedown',
      isEnable(context) { // 不要點擊在 mask 上從新開始
        return !context.isInShape('mask');
      },
      action: ['rect-mask:start', 'rect-mask:show'],
    },
    {
      trigger: 'mask:dragstart',
      action: ['rect-mask:moveStart']
    }
  ],
  processing: [
    {
      trigger: 'plot:mousemove',
      action: ['rect-mask:resize'],
    },
    {
      trigger: 'mask:drag',action: ['rect-mask:move']
    },
    {
      trigger: 'mask:change', action: ['element-range-highlight:highlight']
    }
  ],
  end: [
    { trigger: 'plot:mouseup',
      action: ['rect-mask:end']
    },
    { trigger: 'mask:dragend', action: ['rect-mask:moveEnd']},
    {
      trigger: 'document:mouseup',
      isEnable(context) {
        return !context.isInPlot();
      },
      action: ['element-range-highlight:clear', 'rect-mask:end', 'rect-mask:hide'],
    },
  ],
  rollback: [{ trigger: 'dblclick', action: ['element-range-highlight:clear', 'rect-mask:hide'] }],
}

其餘示例

咱們已經將全部 G2的交互所有經過交互語法進行了組裝,開發交互的效率和質量獲得極大的提高,下面是一些示例: selected.giflegend-error1.gif<br>tooltip-views1.gifview-sync.gifsync-record.gifsync-visible.gif<br>sync-filter3.gifpolygon-brush5.gif

總結

目前 G2 4.0 已經完成上面全部環節的設計和開發,並已經實現 3.x 默認的全部交互,你也能夠自由組合出更多的交互,咱們還將在拖拽組件/視圖重佈局、拖拽圖形重計算、拖拽合併以及圖例排序等方面進行進行交互語法的組裝。G2 4.0將於 2020 年 2月 27 日正式發佈,敬請期待!

G2 官網: https://g2.antv.vision/zh/

github: https://github.com/antvis/G2

相關文章
相關標籤/搜索