summaryrefslogtreecommitdiff
path: root/components/Graph/drawLabels.ts
blob: d2d84f844504f6a296cf37dfb8ca3b1853eca6fd (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { OrgRoamNode } from '../../api'
import { NodeObject } from 'force-graph'
import { initialVisuals } from '../config'
import { hexToRGBA } from '../../pages'
import wrap from 'word-wrap'

export interface drawLabelsProps {
  labelBackgroundColor: string
  labelTextColor: string
  node: NodeObject
  ctx: any
  globalScale: number
  highlightedNodes: { [id: string]: {} }
  previouslyHighlightedNodes: { [id: string]: {} }
  visuals: typeof initialVisuals
  opacity: number
  nodeSize: (node: NodeObject) => number
}
export function drawLabels(props: drawLabelsProps) {
  const {
    labelBackgroundColor,
    labelTextColor,
    node,
    ctx,
    globalScale,
    highlightedNodes,
    previouslyHighlightedNodes,
    visuals,
    opacity,
    nodeSize,
  } = props

  if (!node) {
    return
  }
  //if (dragging) {
  //   return
  //}

  if (!visuals.labels) {
    return
  }
  const wasHighlightedNode = previouslyHighlightedNodes[node.id!]

  if (
    (globalScale <= visuals.labelScale || visuals.labels === 1) &&
    !highlightedNodes[node.id!] &&
    !wasHighlightedNode
  ) {
    return
  }

  const nodeTitle = (node as OrgRoamNode).title!
  const label = nodeTitle.substring(0, visuals.labelLength)
  const fontSize = visuals.labelFontSize / (0.75 * Math.min(Math.max(0.5, globalScale), 3))
  const textWidth = ctx.measureText(label).width
  const bckgDimensions = [textWidth * 1.1, fontSize].map((n) => n + fontSize * 0.5) as [
    number,
    number,
  ] // some padding

  const fadeFactor = Math.min((3 * (globalScale - visuals.labelScale)) / visuals.labelScale, 1)

  // draw label background
  const getLabelOpacity = () => {
    if (visuals.labels === 1) {
      return opacity
    }
    if (globalScale <= visuals.labelScale) {
      return opacity
    }
    return highlightedNodes[node.id!] || previouslyHighlightedNodes[node.id!]
      ? Math.max(fadeFactor, opacity)
      : 1 * fadeFactor * (-1 * (visuals.highlightFade * opacity - 1))
  }
  const nodeS = 8 * Math.cbrt(nodeSize(node) * visuals.nodeRel)
  if (visuals.labelBackgroundColor && visuals.labelBackgroundOpacity) {
    const backgroundOpacity = getLabelOpacity() * visuals.labelBackgroundOpacity
    const labelBackground = hexToRGBA(labelBackgroundColor, backgroundOpacity)
    ctx.fillStyle = labelBackground
    ctx.fillRect(
      node.x! - bckgDimensions[0] / 2,
      node.y! - bckgDimensions[1] / 2 + nodeS,
      ...bckgDimensions,
    )
  }

  // draw label text
  const textOpacity = getLabelOpacity()
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  const labelText = hexToRGBA(labelTextColor, textOpacity)
  ctx.fillStyle = labelText
  ctx.font = `${fontSize}px Sans-Serif`
  const wordsArray = wrap(label, { width: visuals.labelWordWrap }).split('\n')

  const truncatedWords =
    nodeTitle.length > visuals.labelLength
      ? [...wordsArray.slice(0, -1), `${wordsArray.slice(-1)}...`]
      : wordsArray
  truncatedWords.forEach((word, index) => {
    ctx.fillText(word, node.x!, node.y! + nodeS + visuals.labelLineSpace * fontSize * index)
  })
}