Skip to content

Commit

Permalink
Use fuzzy matching for timeline comparisons when there are a differin…
Browse files Browse the repository at this point in the history
…g number of segments (#633)

* Add fuzzy matching to segment names to align on first before falling back to segment number

* Line up timelines based on segment number only if the number of segments are the same, otherwise use fuzzy-matching

* Cleaned up some artifacts from before matchingSplitForTimeline was extracted.

* Don't store all the segment names and segment counts on DOM elements

* Escape HTML entities in the display names so as not to break the fuzzy matching JS

* Handle multiple segments with the same name when using fuzzy matching.

* Default to the first fuzzy-matched segment if some impossible thing happens. Solar flares and the like.
  • Loading branch information
moorecp authored and glacials committed Oct 18, 2019
1 parent 97645df commit ba73148
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
48 changes: 46 additions & 2 deletions app/javascript/timeline.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
import FuzzySet from 'fuzzyset.js'

let currentTimelineRunId = ''
const timelineMouseOverTimers = {}
const timelineMouseOutTimers = {}

const matchingSplitForTimeline = (segment, timeline) => {
if (segment.closest('.timeline-background').getElementsByClassName('split').length === timeline.getElementsByClassName('split').length) {
const split = timeline.querySelector(`.split[data-segment_number='${segment.dataset.segment_number}']`)
if (split) {
return split
}
} else {
const segmentNames = FuzzySet(Array.from(timeline.getElementsByClassName('split')).map(el => el.dataset.segment_name))
const closestSegments = segmentNames.get(segment.dataset.segment_name)
if (closestSegments && closestSegments[0][0] > 0.5) {
// We have at least 1 valid segment.
// We need to see if there are multiple with the same name
const segmentName = closestSegments[0][1]
const segments = Array.from(timeline.querySelectorAll(`.split[data-segment_name='${segmentName}']`))
if (segments.length > 1) {
// There are multiple segments with the same name
// Pick the closest based on segment number
let minDistance = Number.MAX_SAFE_INTEGER
let segmentIndex = 0
segments.forEach((matchedSegment, index) => {
const distance = Math.abs(matchedSegment.dataset.segment_number - segment.dataset.segment_number)
if (distance < minDistance) {
minDistance = distance
segmentIndex = index
}
})
return segments[segmentIndex]
} else {
// Nope, just the 1 segment
return segments[0]
}
}
}
}

const mouseOverSegment = (segment) => {
const run_id = segment.dataset.run_id
const segment_number = segment.dataset.segment_number
const timerKey = `${run_id}-${segment_number}`
timelineMouseOverTimers[timerKey] = undefined

const leftEdge = segment.offsetLeft
const otherTimelinesQuery = `.split[data-segment_number='${segment_number}']:not([data-run_id='${run_id}'])`
document.querySelectorAll(otherTimelinesQuery).forEach((el) => {
const splits = []

document.querySelectorAll(`.timeline-background:not([data-run_id='${run_id}'])`).forEach((timeline) => {
const split = matchingSplitForTimeline(segment, timeline)
if (split) {
splits.push(split)
}
})
splits.forEach((el) => {
const otherLeftEdge = el.offsetLeft
const timeline = el.closest('.timeline-background')
const goldTimeline = timeline.parentElement.querySelector('.gold.timeline')
Expand Down
7 changes: 4 additions & 3 deletions app/views/runs/_timeline.slim
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
- else
- if run.video&.supports_embedding?
div style="height: 1em": span.video-progress-line.timeline-animation id="video-progress-line-#{run.id36}"
- collapsed_segments = run.collapsed_segments(timing)
.timeline-background.timeline-animation data={run_id: run.id36}
.timeline.shadow style="width: #{run.duration(timing) / scale_to * 100.0}%"
- run.collapsed_segments(timing).each.with_index do |segment, index|
- collapsed_segments.each.with_index do |segment, index|
.pure-u.split(
id="#{run.id36}-split-#{index}"
data={start_ms: segment.start(timing).to_ms, run_id: run.id36, segment_number: index+1}
data={start_ms: segment.start(timing).to_ms, run_id: run.id36, segment_name: CGI.escapeHTML(segment.display_name), segment_number: index+1}
class="#{next_timeline_color(run.id36)} #{'progress-bar-striped progress-bar-animated' if segment.duration(timing).nil?}"
style="width: #{segment.proportion(timing) * 100.0}%; z-index: #{index}; #{'cursor: pointer;' if run.video}"
)
Expand All @@ -21,7 +22,7 @@
- else
b In progress
.gold.timeline.timeline-animation style="width: #{run.duration(timing) / scale_to * 100.0}%"
- run.collapsed_segments(timing).each_with_index do |segment, index|
- collapsed_segments.each_with_index do |segment, index|
div style="width: #{segment.proportion(timing) * 100.0}%"
- if segment.shortest_duration(timing).present?
.gold-split style="width: #{segment.shortest_duration(timing) / segment.duration(timing) * 100.0}%"
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"driftless": "^2.0.3",
"expose-loader": "^0.7.5",
"file-saver": "^2.0.2",
"fuzzyset.js": "^0.0.8",
"handlebars": "^4.2.0",
"highcharts": "^7.2.0",
"highcharts-regression": "streamlinesocial/highcharts-regression",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3181,6 +3181,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==

fuzzyset.js@^0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/fuzzyset.js/-/fuzzyset.js-0.0.8.tgz#398311fb54a5f84221db2cb143ac8cf1e523ae50"
integrity sha512-wymI6DYJgCBDFUrIyA/M2gIjJPEWj40pnCf04+Dma0PaprQRrTRh9/Cmz1wl9jCJxA+iqrCqNrGYuq7lVOtzXQ==

gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
Expand Down

0 comments on commit ba73148

Please sign in to comment.