Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new color generation for matches #1311

Merged
merged 8 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion report-viewer/src/components/CodePanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
<td
class="w-full"
:style="{
background: line.match !== null ? line.match.color : 'hsla(0, 0%, 0%, 0)'
background:
line.match !== null
? getMatchColor(0.3, line.match.colorIndex)
: 'hsla(0, 0%, 0%, 0)'
}"
>
<pre v-html="line.line" class="code-font !bg-transparent" ref="lineRefs"></pre>
Expand All @@ -52,6 +55,7 @@ import type { Match } from '@/model/Match'
import type { SubmissionFile } from '@/stores/state'
import { highlight } from '@/utils/CodeHighlighter'
import type { HighlightLanguage } from '@/model/Language'
import { getMatchColor } from '@/utils/ColorUtils'

const props = defineProps({
/**
Expand Down
3 changes: 2 additions & 1 deletion report-viewer/src/components/MatchList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

<div class="flex w-full flex-row space-x-1 overflow-x-auto">
<OptionComponent
:style="{ background: match.color }"
v-for="[index, match] in matches?.entries()"
:style="{ background: getMatchColor(0.3, match.colorIndex) }"
v-bind:key="index"
@click="$emit('matchSelected', match)"
:label="
Expand All @@ -30,6 +30,7 @@
import type { Match } from '@/model/Match'
import OptionComponent from './optionsSelectors/OptionComponent.vue'
import ToolTipComponent from './ToolTipComponent.vue'
import { getMatchColor } from '@/utils/ColorUtils'

defineProps({
/**
Expand Down
6 changes: 3 additions & 3 deletions report-viewer/src/model/Match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
* @property startInSecond - Starting line of the match in the second file.
* @property endInSecond - Ending line of the match in the second file.
* @property tokens - Number of tokens in the match.
* @property color - Color of the match.
* @property colorIndex - Index of the color to use for the match.
*/
export type Match = {
export interface Match {
firstFile: string
secondFile: string
startInFirst: number
endInFirst: number
startInSecond: number
endInSecond: number
tokens: number
color: string
colorIndex?: number
TwoOfTwelve marked this conversation as resolved.
Show resolved Hide resolved
}
56 changes: 46 additions & 10 deletions report-viewer/src/model/factories/ComparisonFactory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Comparison } from '../Comparison'
import type { Match } from '../Match'
import { store } from '@/stores/store'
import { generateColors } from '@/utils/ColorUtils'
import { getMatchColorCount } from '@/utils/ColorUtils'
import slash from 'slash'
import { BaseFactory } from './BaseFactory'
import { MetricType } from '../MetricType'
Expand Down Expand Up @@ -35,19 +35,15 @@ export class ComparisonFactory extends BaseFactory {

const matches = json.matches as Array<Record<string, unknown>>

const matchSaturation = 0.8
const matchLightness = 0.5
const matchAlpha = 0.3
const colors = generateColors(matches.length, matchSaturation, matchLightness, matchAlpha)
const coloredMatches = matches.map((match, index) => this.mapMatch(match, colors[index]))
const unColoredMatches = matches.map((match) => this.getMatch(match))

return new Comparison(
firstSubmissionId,
secondSubmissionId,
this.extractSimilarities(json),
filesOfFirstSubmission,
filesOfSecondSubmission,
coloredMatches
this.colorMatches(unColoredMatches)
)
}

Expand Down Expand Up @@ -101,16 +97,56 @@ export class ComparisonFactory extends BaseFactory {
}
}

private static mapMatch(match: Record<string, unknown>, color: string): Match {
private static getMatch(match: Record<string, unknown>): Match {
return {
firstFile: slash(match.file1 as string),
secondFile: slash(match.file2 as string),
startInFirst: match.start1 as number,
endInFirst: match.end1 as number,
startInSecond: match.start2 as number,
endInSecond: match.end2 as number,
tokens: match.tokens as number,
color: color
tokens: match.tokens as number
}
}

private static colorMatches(matches: Match[]): Match[] {
const maxColorCount = getMatchColorCount()
let currentColorIndex = 0
const matchesFirst = Array.from(matches)
.sort((a, b) => a.startInFirst - b.startInFirst)
.sort((a, b) => (a.firstFile > b.firstFile ? 1 : -1))
const matchesSecond = Array.from(matches)
.sort((a, b) => a.startInSecond - b.startInSecond)
.sort((a, b) => (a.secondFile > b.secondFile ? 1 : -1))
const sortedSize = Array.from(matches).sort((a, b) => b.tokens - a.tokens)

function isColorAvailable(matchList: Match[], index: number) {
return (
(index === 0 || matchList[index - 1].colorIndex !== currentColorIndex) &&
(index === matchList.length - 1 || matchList[index + 1].colorIndex !== currentColorIndex)
)
}

for (let i = 0; i < matches.length; i++) {
const firstIndex = matchesFirst.findIndex((match) => match === matches[i])
const secondIndex = matchesSecond.findIndex((match) => match === matches[i])
const sortedIndex = sortedSize.findIndex((match) => match === matches[i])
const startCounter = currentColorIndex
while (
!isColorAvailable(matchesFirst, firstIndex) ||
!isColorAvailable(matchesSecond, secondIndex) ||
!isColorAvailable(sortedSize, sortedIndex)
) {
currentColorIndex = (currentColorIndex + 1) % maxColorCount

if (currentColorIndex == startCounter) {
// This case should never happen, this is just a safety measure
throw currentColorIndex
}
}
matches[i].colorIndex = currentColorIndex
currentColorIndex = (currentColorIndex + 1) % maxColorCount
}
return sortedSize
}
}
24 changes: 23 additions & 1 deletion report-viewer/src/utils/ColorUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ function generateColorsForInterval(
return colors
}

/** This is the list of colors that are used as the background colot of matches in the comparison view */
const matchColors: { red: number; green: number; blue: number }[] = [
Kr0nox marked this conversation as resolved.
Show resolved Hide resolved
{ red: 255, green: 122, blue: 0 },
{ red: 0, green: 133, blue: 255 },
{ red: 255, green: 0, blue: 122 },
{ red: 255, green: 245, blue: 0 },
{ red: 0, green: 255, blue: 255 },
{ red: 112, green: 0, blue: 255 },
{ red: 0, green: 255, blue: 133 }
]

function getMatchColorCount() {
return matchColors.length
}

function getMatchColor(alpha: number, index?: number) {
if (index == undefined) {
return 'rgba(0,0,0,0)'
}
return `rgba(${matchColors[index].red}, ${matchColors[index].green}, ${matchColors[index].blue}, ${alpha})`
}

const graphColors = {
ticksAndFont: computed(() => {
return store().uiState.useDarkMode ? '#ffffff' : '#000000'
Expand All @@ -71,4 +93,4 @@ const graphColors = {
pointFill: 'rgba(190, 22, 34, 1)'
}

export { generateColors, graphColors }
export { generateColors, graphColors, getMatchColorCount, getMatchColor }