utils.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import { hierarchy } from 'd3-hierarchy'
  2. const dateFormatter = new Intl.DateTimeFormat('fr-FR', { month: 'long', year: 'numeric' })
  3. export const RELATIONS = [
  4. 'parents',
  5. 'siblings',
  6. 'creation_siblings',
  7. 'children'
  8. ]
  9. export const DATA_LEVELS = {
  10. initial: 0,
  11. partial: 1,
  12. full: 2
  13. }
  14. export const ID_VARIANTS = {
  15. 9: 'depart',
  16. 22: 'critique',
  17. 63: 'echo',
  18. 6: 'reflexion',
  19. 7: 'lecture',
  20. 8: 'sensible',
  21. 23: 'kit',
  22. 0: 'creation'
  23. }
  24. export const VARIANT_IDS = Object.fromEntries(
  25. Object.entries(ID_VARIANTS).map(([key, value]) => [value, parseInt(key)])
  26. )
  27. export const SEARCH_KEYS = ['content', 'title', 'preTitle', 'authors']
  28. export function formatDate (date) {
  29. return dateFormatter.format(new Date(date))
  30. }
  31. export function parseNodesQueryParams ({ mode, nodes = [] }) {
  32. let nodebook = typeof nodes === 'string' ? [nodes] : nodes
  33. nodebook = nodebook.map(ids => {
  34. return typeof ids === 'string'
  35. ? ids.split(',').map(id => parseInt(id))
  36. : [...ids]
  37. })
  38. return { mode, nodebook }
  39. }
  40. export function reduceQueryLevels (lvl, lowestLvl = -1) {
  41. return Array(lvl - lowestLvl).fill(lowestLvl + 1).map((v, i) => v + i)
  42. }
  43. export function reduceQueryIds (ids, dataLevel, data) {
  44. const lvl = DATA_LEVELS[dataLevel]
  45. const idsToQuery = []
  46. let lowestLvl = lvl
  47. for (const id of ids) {
  48. const nodeLvl = id in data ? data[id].dataLevel : -1
  49. if (nodeLvl < lvl) {
  50. idsToQuery.push(id)
  51. }
  52. if (nodeLvl < lowestLvl) {
  53. lowestLvl = nodeLvl
  54. }
  55. }
  56. return idsToQuery.length === 0 ? {} : {
  57. idsToQuery,
  58. levelsToQuery: reduceQueryLevels(lvl, lowestLvl)
  59. }
  60. }
  61. export function getUniqueNodesIds (tree) {
  62. function extractId (ids, node) {
  63. ids.add(node.id)
  64. for (const relation of RELATIONS) {
  65. if (relation in node && node[relation]) {
  66. for (const subNode of node[relation]) {
  67. extractId(ids, subNode)
  68. }
  69. }
  70. }
  71. return ids
  72. }
  73. return Array.from(extractId(new Set(), tree))
  74. }
  75. export function getRelatedNodesIds (nodes, ignored) {
  76. const ids = new Set()
  77. for (const node of nodes) {
  78. for (const relation of RELATIONS) {
  79. if (relation in node && node[relation]) {
  80. node[relation].forEach(({ id }) => {
  81. if (ignored.includes(id)) return
  82. ids.add(id)
  83. })
  84. }
  85. }
  86. }
  87. return Array.from(ids)
  88. }
  89. export function getRandomIds (ids, count = 3) {
  90. const randomIds = []
  91. while (randomIds.length < count) {
  92. const id = ids[Math.floor(Math.random() * ids.length)]
  93. if (!randomIds.includes(id)) {
  94. randomIds.push(id)
  95. }
  96. }
  97. return randomIds
  98. }
  99. export function parseTree (treeData) {
  100. if ('creations' in treeData) {
  101. if (treeData.creations) {
  102. if (!Array.isArray(treeData.children)) {
  103. treeData.children = []
  104. }
  105. treeData.creations.forEach(item => {
  106. item.variant = [{ id: 0 }]
  107. treeData.children.push(item)
  108. })
  109. }
  110. delete treeData.creations
  111. }
  112. for (const relation of RELATIONS) {
  113. if (relation in treeData && treeData[relation]) {
  114. treeData[relation] = treeData[relation].map(node => parseTree(node))
  115. }
  116. }
  117. return treeData
  118. }
  119. export function buildTree (treeData, nodesData) {
  120. const uniqueIds = []
  121. const nodes = []
  122. const links = []
  123. const h = hierarchy(treeData, (node) => {
  124. return RELATIONS.reduce((acc, relation) => {
  125. if (node[relation]) {
  126. node[relation].forEach((item, i) => {
  127. item.linkType = relation
  128. })
  129. return [...acc, ...node[relation]]
  130. }
  131. return acc
  132. }, [])
  133. })
  134. h.each(node => {
  135. node.id = node.data.id
  136. if (!uniqueIds.includes(node.id)) {
  137. uniqueIds.push(node.id)
  138. node.data = nodesData.find(n => n.id === node.id)
  139. // Add `x` and `y` keys so Vue can update on these values updates
  140. Object.assign(node, { x: undefined, y: undefined })
  141. nodes.push(node)
  142. if (node.children) {
  143. node.children.forEach(child => {
  144. const asSource = links.find(link => link.source === node.id && link.target === child.data.id)
  145. const asTarget = links.find(link => link.source === child.data.id && link.target === node.id)
  146. if (!asSource && !asTarget) {
  147. links.push({ source: node.id, target: child.data.id, linkType: child.data.linkType })
  148. }
  149. })
  150. }
  151. }
  152. })
  153. return {
  154. nodes,
  155. links
  156. }
  157. }
  158. export function searchInNode (search, node) {
  159. if (!search) return true
  160. for (const key of SEARCH_KEYS) {
  161. if (!node[key]) continue
  162. let match = false
  163. if (key === 'authors') {
  164. match = node[key].some(author => author.name.toLowerCase().includes(search))
  165. } else {
  166. match = node[key].toLowerCase().includes(search)
  167. }
  168. if (match) return true
  169. }
  170. return false
  171. }
  172. export function tagsInNode (tags, nodeTags) {
  173. if (tags.length === 0) return true
  174. if (!nodeTags || nodeTags.length === 0) return false
  175. return tags.every(tag => nodeTags.some(nodeTag => nodeTag.name === tag))
  176. }
  177. export function getRelation (node) {
  178. if (node.type === 'prod' && node.parents && node.parents.length) {
  179. return { parentId: node.parents[0].id, childId: node.id }
  180. }
  181. return { parentId: node.id }
  182. }
  183. export function getStrangenessOpacity (currentStrangeness, node) {
  184. if (currentStrangeness === undefined) return 1
  185. const strangeness = (
  186. node.type === 'prod' && node.parents && node.parents.length ? node.parents[0] : node
  187. ).strangeness
  188. return 1 / (Math.abs(strangeness - currentStrangeness) + 1)
  189. }