Skip to content

Commit

Permalink
Merge pull request #181 from Cryptkeeper/release-551
Browse files Browse the repository at this point in the history
5.5.1 release preview
  • Loading branch information
Cryptkeeper authored Jun 10, 2020
2 parents 2336c9f + 21539c3 commit b7ed5fd
Show file tree
Hide file tree
Showing 13 changed files with 1,132 additions and 377 deletions.
4 changes: 2 additions & 2 deletions assets/js/favorites.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class FavoritesManager {
serverRegistration.isFavorite = true

// Update icon since by default it is unfavorited
document.getElementById('favorite-toggle_' + serverRegistration.serverId).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
document.getElementById(`favorite-toggle_${serverRegistration.serverId}`).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
}
}
}
Expand All @@ -47,7 +47,7 @@ export class FavoritesManager {
serverRegistration.isFavorite = !serverRegistration.isFavorite

// Update the displayed favorite icon
document.getElementById('favorite-toggle_' + serverRegistration.serverId).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))
document.getElementById(`favorite-toggle_${serverRegistration.serverId}`).setAttribute('class', this.getIconClass(serverRegistration.isFavorite))

// Request the app controller instantly re-sort the server listing
// This handles the favorite sorting logic internally
Expand Down
141 changes: 100 additions & 41 deletions assets/js/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import uPlot from 'uplot'
import { RelativeScale } from './scale'

import { formatNumber, formatTimestampSeconds } from './util'
import { uPlotTooltipPlugin } from './tooltip'
import { uPlotTooltipPlugin, uPlotIsZoomedPlugin } from './plugins'

import { FAVORITE_SERVERS_STORAGE_KEY } from './favorites'

Expand All @@ -18,6 +18,7 @@ export class GraphDisplayManager {
this._hasLoadedSettings = false
this._initEventListenersOnce = false
this._showOnlyFavorites = false
this._isPlotZoomed = false
}

addGraphPoint (timestamp, playerCounts) {
Expand Down Expand Up @@ -49,11 +50,14 @@ export class GraphDisplayManager {
}
}

// Paint updated data structure
this._plotInstance.setData([
this._graphTimestamps,
...this._graphData
])
// If not zoomed, paint updated data structure
// Otherwise flag the plot data as dirty with repainting to be handled by #handlePlotZoomOut
// This prevents #addGraphPoint calls from resetting the graph's zoom state
if (!this._isPlotZoomed) {
this._plotInstance.setData(this.getGraphData())
} else {
this._isPlotZoomedDataDirty = true
}
}

loadLocalStorage () {
Expand Down Expand Up @@ -127,13 +131,51 @@ export class GraphDisplayManager {
}
}

getGraphData () {
return [
this._graphTimestamps,
...this._graphData
]
}

getGraphDataPoint (serverId, index) {
const graphData = this._graphData[serverId]
if (graphData && index < graphData.length && typeof graphData[index] === 'number') {
return graphData[index]
}
}

getClosestPlotSeriesIndex (idx) {
let closestSeriesIndex = -1
let closestSeriesDist = Number.MAX_VALUE

const plotHeight = this._plotInstance.bbox.height / devicePixelRatio

for (let i = 1; i < this._plotInstance.series.length; i++) {
const series = this._plotInstance.series[i]

if (!series.show) {
continue
}

const point = this._plotInstance.data[i][idx]

if (typeof point === 'number') {
const scale = this._plotInstance.scales[series.scale]
const posY = (1 - ((point - scale.min) / (scale.max - scale.min))) * plotHeight

const dist = Math.abs(posY - this._plotInstance.cursor.top)

if (dist < closestSeriesDist) {
closestSeriesIndex = i
closestSeriesDist = dist
}
}
}

return closestSeriesIndex
}

buildPlotInstance (timestamps, data) {
// Lazy load settings from localStorage, if any and if enabled
if (!this._hasLoadedSettings) {
Expand All @@ -142,6 +184,19 @@ export class GraphDisplayManager {
this.loadLocalStorage()
}

for (const playerCounts of data) {
// Each playerCounts value corresponds to a ServerRegistration
// Require each array is the length of timestamps, if not, pad at the start with null values to fit to length
// This ensures newer ServerRegistrations do not left align due to a lower length
const lengthDiff = timestamps.length - playerCounts.length

if (lengthDiff > 0) {
const padding = Array(lengthDiff).fill(null)

playerCounts.unshift(...padding)
}
}

this._graphTimestamps = timestamps
this._graphData = data

Expand All @@ -150,7 +205,7 @@ export class GraphDisplayManager {
scale: 'Players',
stroke: serverRegistration.data.color,
width: 2,
value: (_, raw) => formatNumber(raw) + ' Players',
value: (_, raw) => `${formatNumber(raw)} Players`,
show: serverRegistration.isVisible,
spanGaps: true,
points: {
Expand All @@ -165,50 +220,39 @@ export class GraphDisplayManager {
// eslint-disable-next-line new-cap
this._plotInstance = new uPlot({
plugins: [
uPlotTooltipPlugin((pos, id) => {
uPlotTooltipPlugin((pos, idx) => {
if (pos) {
let text = this._app.serverRegistry.getServerRegistrations()
const closestSeriesIndex = this.getClosestPlotSeriesIndex(idx)

const text = this._app.serverRegistry.getServerRegistrations()
.filter(serverRegistration => serverRegistration.isVisible)
.sort((a, b) => {
if (a.isFavorite !== b.isFavorite) {
return a.isFavorite ? -1 : 1
}

const aPoint = this.getGraphDataPoint(a.serverId, id)
const bPoint = this.getGraphDataPoint(b.serverId, id)

if (typeof aPoint === typeof bPoint) {
if (typeof aPoint === 'undefined') {
return 0
}
} else {
return typeof aPoint === 'number' ? -1 : 1
return a.data.name.localeCompare(b.data.name)
}

return bPoint - aPoint
})
.map(serverRegistration => {
const point = this.getGraphDataPoint(serverRegistration.serverId, id)
const point = this.getGraphDataPoint(serverRegistration.serverId, idx)

let serverName = serverRegistration.data.name
if (serverRegistration.isFavorite) {
serverName = '<span class="' + this._app.favoritesManager.getIconClass(true) + '"></span> ' + serverName
if (closestSeriesIndex === serverRegistration.getGraphDataIndex()) {
serverName = `<strong>${serverName}</strong>`
}

if (typeof point === 'number') {
return serverName + ': ' + formatNumber(point)
} else {
return serverName + ': -'
if (serverRegistration.isFavorite) {
serverName = `<span class="${this._app.favoritesManager.getIconClass(true)}"></span> ${serverName}`
}
}).join('<br>')

text += '<br><br><strong>' + formatTimestampSeconds(this._graphTimestamps[id]) + '</strong>'
return `${serverName}: ${formatNumber(point)}`
}).join('<br>') + `<br><br><strong>${formatTimestampSeconds(this._graphTimestamps[idx])}</strong>`

this._app.tooltip.set(pos.left, pos.top, 10, 10, text)
} else {
this._app.tooltip.hide()
}
})
}),
uPlotIsZoomedPlugin(this.handlePlotZoomIn, this.handlePlotZoomOut)
],
...this.getPlotSize(),
cursor: {
Expand Down Expand Up @@ -238,8 +282,8 @@ export class GraphDisplayManager {
},
split: () => {
const visibleGraphData = this.getVisibleGraphData()
const [, max, scale] = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
const ticks = RelativeScale.generateTicks(0, max, scale)
const { scaledMax, scale } = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
const ticks = RelativeScale.generateTicks(0, scaledMax, scale)
return ticks
}
}
Expand All @@ -249,18 +293,15 @@ export class GraphDisplayManager {
auto: false,
range: () => {
const visibleGraphData = this.getVisibleGraphData()
const [, scaledMax] = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
return [0, scaledMax]
const { scaledMin, scaledMax } = RelativeScale.scaleMatrix(visibleGraphData, tickCount, maxFactor)
return [scaledMin, scaledMax]
}
}
},
legend: {
show: false
}
}, [
this._graphTimestamps,
...this._graphData
], document.getElementById('big-graph'))
}, this.getGraphData(), document.getElementById('big-graph'))

// Show the settings-toggle element
document.getElementById('settings-toggle').style.display = 'inline-block'
Expand All @@ -273,7 +314,7 @@ export class GraphDisplayManager {

// Copy application state into the series data used by uPlot
for (const serverRegistration of this._app.serverRegistry.getServerRegistrations()) {
this._plotInstance.series[serverRegistration.serverId + 1].show = serverRegistration.isVisible
this._plotInstance.series[serverRegistration.getGraphDataIndex()].show = serverRegistration.isVisible
}

this._plotInstance.redraw()
Expand Down Expand Up @@ -306,6 +347,21 @@ export class GraphDisplayManager {
this._resizeRequestTimeout = undefined
}

handlePlotZoomIn = () => {
this._isPlotZoomed = true
}

handlePlotZoomOut = () => {
this._isPlotZoomed = false

// Test if the data has changed while the plot was zoomed in
if (this._isPlotZoomedDataDirty) {
this._isPlotZoomedDataDirty = false

this._plotInstance.setData(this.getGraphData())
}
}

initEventListeners () {
if (!this._initEventListenersOnce) {
this._initEventListenersOnce = true
Expand Down Expand Up @@ -413,6 +469,9 @@ export class GraphDisplayManager {
this._graphData = []
this._hasLoadedSettings = false

this._isPlotZoomed = false
this._isPlotZoomedDataDirty = false

// Fire #clearTimeout if the timeout is currently defined
if (this._resizeRequestTimeout) {
clearTimeout(this._resizeRequestTimeout)
Expand Down
4 changes: 2 additions & 2 deletions assets/js/mojang.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export class MojangUpdater {

updateServiceStatus (name, title) {
// HACK: ensure mojang-status is added for alignment, replace existing class to swap status color
document.getElementById('mojang-status_' + name).setAttribute('class', MOJANG_STATUS_BASE_CLASS + ' mojang-status-' + title.toLowerCase())
document.getElementById('mojang-status-text_' + name).innerText = title
document.getElementById(`mojang-status_${name}`).setAttribute('class', `${MOJANG_STATUS_BASE_CLASS} mojang-status-${title.toLowerCase()}`)
document.getElementById(`mojang-status-text_${name}`).innerText = title
}

reset () {
Expand Down
21 changes: 12 additions & 9 deletions assets/js/percbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ export class PercentageBar {

// Update position/width
// leftPadding is a sum of previous iterations width value
const div = document.getElementById('perc-bar-part_' + serverRegistration.serverId) || this.createPart(serverRegistration)
const div = document.getElementById(`perc-bar-part_${serverRegistration.serverId}`) || this.createPart(serverRegistration)

const widthPixels = `${width}px`
const leftPaddingPixels = `${leftPadding}px`

// Only redraw if needed
if (div.style.width !== width + 'px' || div.style.left !== leftPadding + 'px') {
div.style.width = width + 'px'
div.style.left = leftPadding + 'px'
if (div.style.width !== widthPixels || div.style.left !== leftPaddingPixels) {
div.style.width = widthPixels
div.style.left = leftPaddingPixels
}

leftPadding += width
Expand All @@ -35,7 +38,7 @@ export class PercentageBar {
createPart (serverRegistration) {
const div = document.createElement('div')

div.id = 'perc-bar-part_' + serverRegistration.serverId
div.id = `perc-bar-part_${serverRegistration.serverId}`
div.style.background = serverRegistration.data.color

div.setAttribute('class', 'perc-bar-part')
Expand All @@ -55,10 +58,10 @@ export class PercentageBar {
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverId)

this._app.tooltip.set(event.target.offsetLeft, event.target.offsetTop, 10, this._parent.offsetTop + this._parent.offsetHeight + 10,
(typeof serverRegistration.rankIndex !== 'undefined' ? '#' + (serverRegistration.rankIndex + 1) + ' ' : '') +
serverRegistration.data.name +
'<br>' + formatNumber(serverRegistration.playerCount) + ' Players<br>' +
'<strong>' + formatPercent(serverRegistration.playerCount, this._app.getTotalPlayerCount()) + '</strong>')
`${typeof serverRegistration.rankIndex !== 'undefined' ? `#${serverRegistration.rankIndex + 1} ` : ''}
${serverRegistration.data.name}<br>
${formatNumber(serverRegistration.playerCount)} Players<br>
<strong>${formatPercent(serverRegistration.playerCount, this._app.getTotalPlayerCount())}</strong>`)
}

handleMouseOut = () => {
Expand Down
24 changes: 24 additions & 0 deletions assets/js/tooltip.js → assets/js/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,27 @@ export function uPlotTooltipPlugin (onHover) {
}
}
}

export function uPlotIsZoomedPlugin (onZoomIn, onZoomOut) {
return {
hooks: {
setSelect: u => {
u._zoomPluginIgnoreNextSetScale = true

if (onZoomIn) {
onZoomIn(u)
}
},
setScale: u => {
if (typeof u._zoomPluginIgnoreNextSetScale !== 'boolean') {
return
}
if (u._zoomPluginIgnoreNextSetScale) {
u._zoomPluginIgnoreNextSetScale = false
} else if (onZoomOut) {
onZoomOut(u)
}
}
}
}
}
Loading

0 comments on commit b7ed5fd

Please sign in to comment.