Files
Superalgos/ViewPort.js
T

440 lines
12 KiB
JavaScript


function newViewPort () {
const MODULE_NAME = 'Viewport'
const INFO_LOG = false
const INTENSIVE_LOG = false
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
const CONSOLE_LOG = true
let ANIMATION_INCREMENT = 0.25
const TOP_MARGIN = 15 + TOP_SPACE_HEIGHT
const BOTTOM_MARGIN = 15 + BOTTOM_SPACE_HEIGHT
const LEFT_MARGIN = 50
const RIGHT_MARGIN = 50
const MARGINS = {
TOP: TOP_MARGIN,
BOTTOM: BOTTOM_MARGIN,
LEFT: LEFT_MARGIN,
RIGHT: RIGHT_MARGIN
}
let thisObject = {
visibleArea: undefined,
width: undefined,
height: undefined,
eventHandler: undefined,
zoomTargetLevel: undefined,
zoomLevel: undefined,
mousePosition: undefined,
margins: MARGINS,
getDisplacement: getDisplacement,
newZoomLevel: newZoomLevel,
applyZoom: applyZoom,
isMinZoom: isMinZoom,
zoomFontSize: zoomFontSize,
zoomThisPoint: zoomThisPoint,
unzoomThisPoint: unzoomThisPoint,
isThisPointVisible: isThisPointVisible,
fitIntoVisibleArea: fitIntoVisibleArea,
displace: displace,
displaceTarget: displaceTarget,
animate: animate,
draw: draw,
raiseEvents: raiseEvents,
initialize: initialize
}
let increment = 0.035
let offset = {
x: 0,
y: 0
}
var targetOffset = {
x: 0,
y: 0
}
let offsetIncrement = {
x: 0,
y: 0
}
thisObject.mousePosition = {
x: 0,
y: 0
}
thisObject.eventHandler = newEventHandler()
let objectStorage = {}
return thisObject
function initialize () {
thisObject.visibleArea = {
topLeft: { x: LEFT_MARGIN, y: TOP_MARGIN },
topRight: { x: browserCanvas.width - RIGHT_MARGIN, y: TOP_MARGIN },
bottomRight: { x: browserCanvas.width - RIGHT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN},
bottomLeft: { x: LEFT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN}
}
thisObject.width = thisObject.visibleArea.topRight.x - thisObject.visibleArea.topLeft.x
thisObject.height = thisObject.visibleArea.bottomRight.y - thisObject.visibleArea.topLeft.y
readObjectState()
}
function getDisplacement () {
let displacement = {
x: offset.x,
y: offset.y
}
return displacement
}
function raiseEvents () {
let event = {
newOffset: offset
}
thisObject.eventHandler.raiseEvent('Offset Changed', event)
}
function animate () {
if (thisObject.zoomLevel < thisObject.zoomTargetLevel) {
if (thisObject.zoomTargetLevel - thisObject.zoomLevel < ANIMATION_INCREMENT) {
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel)
}
thisObject.zoomLevel = thisObject.zoomLevel + ANIMATION_INCREMENT
changeZoom(thisObject.zoomLevel - ANIMATION_INCREMENT, thisObject.zoomLevel)
}
if (thisObject.zoomLevel > thisObject.zoomTargetLevel) {
if (thisObject.zoomLevel - thisObject.zoomTargetLevel < ANIMATION_INCREMENT) {
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel)
}
thisObject.zoomLevel = thisObject.zoomLevel - ANIMATION_INCREMENT
changeZoom(thisObject.zoomLevel + ANIMATION_INCREMENT, thisObject.zoomLevel)
}
if (offsetIncrement.y !== 0) {
if (Math.trunc(Math.abs(targetOffset.y - offset.y) * 1000) >= Math.trunc(Math.abs(offsetIncrement.y) * 1000)) {
offset.y = offset.y + offsetIncrement.y
// console.log("offset.y changed to " + offset.y)
} else {
offsetIncrement.y = 0
}
}
}
function displace (displaceVector) {
offset.x = offset.x + displaceVector.x
offset.y = offset.y + displaceVector.y
saveObjectState()
let event = {
newOffset: offset
}
thisObject.eventHandler.raiseEvent('Offset Changed', event)
// console.log("displace produced new Offset x = " + offset.x + " y = " + offset.y);
}
function displaceTarget (displaceVector) {
targetOffset.x = targetOffset.x + displaceVector.x
targetOffset.y = targetOffset.y + displaceVector.y
offsetIncrement = {
x: (targetOffset.x - offset.x) / 10,
y: (targetOffset.y - offset.y) / 10
}
// console.log("displaceTarget x = " + targetOffset.x + " y = " + targetOffset.y);
}
function newZoomLevel (level) {
thisObject.zoomTargetLevel = level
thisObject.zoomLevel = level
saveObjectState()
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) / 3
let event = {
newLevel: thisObject.zoomTargetLevel,
newOffset: offset,
type: undefined
}
thisObject.eventHandler.raiseEvent('Zoom Changed', event)
return true
}
function isMinZoom () {
/* returns true is we are currently at the min zoom level. */
if (thisObject.zoomTargetLevel === MIN_ZOOM_LEVEL) { return true } else { return false }
}
function applyZoom (amount) {
// console.log("applyZoom amount: " + amount);
if (amount > 0) {
if (thisObject.zoomTargetLevel > -5) {
amount = amount * 2
}
if (thisObject.zoomTargetLevel > 10) {
amount = amount * 3
}
if (thisObject.zoomTargetLevel > 15) {
amount = amount * 4
}
}
if (amount < 0) {
if (thisObject.zoomTargetLevel > -4) {
amount = amount * 2
}
if (thisObject.zoomTargetLevel > 13) {
amount = amount * 3
}
if (thisObject.zoomTargetLevel > 19) {
amount = amount * 4
}
}
if (thisObject.zoomTargetLevel + amount > 1000) {
return false
}
if (thisObject.zoomTargetLevel <= -27 && amount < 0) {
amount = amount / 4
}
if (thisObject.zoomTargetLevel < -27 && amount > 0) {
amount = amount / 4
}
if (thisObject.zoomTargetLevel + amount < MIN_ZOOM_LEVEL) {
return false
}
thisObject.zoomTargetLevel = thisObject.zoomTargetLevel + amount
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) / 3
let event = {
newLevel: thisObject.zoomTargetLevel,
newOffset: offset,
type: undefined
}
if (amount > 0) {
event.type = 'Zoom In'
} else {
event.type = 'Zoom Out'
}
thisObject.eventHandler.raiseEvent('Zoom Changed', event)
return true
}
function changeZoom (oldLevel, newLevel) {
let mouseNoZoom = unzoomThisPoint(thisObject.mousePosition, oldLevel)
let newMouse = zoomThisPoint(mouseNoZoom, newLevel)
offset.x = offset.x - newMouse.x + thisObject.mousePosition.x
offset.y = offset.y - newMouse.y + thisObject.mousePosition.y
saveObjectState()
targetOffset.x = offset.x
targetOffset.y = offset.y
offsetIncrement = {
x: 0,
y: 0
}
}
function zoomFontSize (baseSize, level) {
let zoomFactor = increment // + increment * thisObject.zoomLevel / 100;
if (level === undefined) {
baseSize = baseSize * (1 + zoomFactor * thisObject.zoomLevel)
} else {
baseSize = baseSize * (1 + zoomFactor * level)
}
return baseSize
}
function fitIntoVisibleArea (point) {
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
if (point.x > thisObject.visibleArea.bottomRight.x + 1) {
point.x = thisObject.visibleArea.bottomRight.x + 1
}
if (point.x < thisObject.visibleArea.topLeft.x - 1) {
point.x = thisObject.visibleArea.topLeft.x - 1
}
if (point.y > thisObject.visibleArea.bottomRight.y + 1) {
point.y = thisObject.visibleArea.bottomRight.y + 1
}
if (point.y < thisObject.visibleArea.topLeft.y - 1) {
point.y = thisObject.visibleArea.topLeft.y - 1
}
return point
}
function zoomThisPoint (point, level) {
let zoomFactor = increment // + increment * thisObject.zoomLevel / 100;
if (level === undefined) {
point.x = point.x * (1 + zoomFactor * thisObject.zoomLevel) + offset.x
point.y = point.y * (1 + zoomFactor * thisObject.zoomLevel) + offset.y
} else {
point.x = point.x * (1 + zoomFactor * level) + offset.x
point.y = point.y * (1 + zoomFactor * level) + offset.y
}
return point
}
function unzoomThisPoint (pointWithZoom, level) {
let pointWithoutZoom
let zoomFactor = increment // + increment * thisObject.zoomLevel / 100;
if (level === undefined) {
pointWithoutZoom = {
x: (pointWithZoom.x - offset.x) / (1 + zoomFactor * thisObject.zoomLevel),
y: (pointWithZoom.y - offset.y) / (1 + zoomFactor * thisObject.zoomLevel)
}
} else {
pointWithoutZoom = {
x: (pointWithZoom.x - offset.x) / (1 + zoomFactor * level),
y: (pointWithZoom.y - offset.y) / (1 + zoomFactor * level)
}
}
return pointWithoutZoom
}
function isThisPointVisible (point) {
if (visibleArea === undefined) {
getVisibleArea()
}
if (point.x < visibleArea.topLeft.x || point.x > visibleArea.bottomRight.x || point.y < visibleArea.topLeft.y || point.y > visibleArea.bottomRight.y) {
return false
} else {
return true
}
}
function draw () {
drawGrid(0.1)
}
function drawGrid (step) {
if (thisObject.zoomLevel > -17) { return }
let squareWidth = (thisObject.visibleArea.bottomRight.x - thisObject.visibleArea.bottomLeft.x) / step
squareWidth = squareWidth + squareWidth * increment * thisObject.zoomLevel
let startingX = offset.x - Math.trunc(offset.x / squareWidth) * squareWidth
let startingY = offset.y - Math.trunc(offset.y / squareWidth) * squareWidth
let lineWidth = 0.4 + thisObject.zoomLevel / 100
lineWidth = lineWidth.toFixed(2)
if (lineWidth < 0.1) {
return
}
if (lineWidth > 2) {
lineWidth = 2
}
browserCanvasContext.beginPath()
let CROSS_SIZE = 4
for (var i = startingX; i < thisObject.visibleArea.bottomRight.x + RIGHT_MARGIN; i = i + squareWidth) {
for (var j = startingY; j < thisObject.visibleArea.bottomRight.y + BOTTOM_MARGIN; j = j + squareWidth) {
let point1 = {
x: Math.trunc(i - CROSS_SIZE),
y: Math.trunc(j)
}
let point2 = {
x: Math.trunc(i + CROSS_SIZE),
y: Math.trunc(j)
}
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
let point3 = {
x: Math.trunc(i),
y: Math.trunc(j - CROSS_SIZE)
}
let point4 = {
x: Math.trunc(i),
y: Math.trunc(j + CROSS_SIZE)
}
browserCanvasContext.moveTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
}
}
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(150, 150, 150, 0.5)'
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
}
function saveObjectState () {
objectStorage.offset = offset
objectStorage.zoomLevel = thisObject.zoomLevel
window.localStorage.setItem(MODULE_NAME, JSON.stringify(objectStorage))
}
function readObjectState () {
let objectStorageString = window.localStorage.getItem(MODULE_NAME)
if (objectStorageString !== null && objectStorageString !== '') {
objectStorage = JSON.parse(objectStorageString)
offset = objectStorage.offset
thisObject.zoomLevel = objectStorage.zoomLevel
thisObject.zoomTargetLevel = objectStorage.zoomLevel
INITIAL_TIME_PERIOD = recalculatePeriod(thisObject.zoomLevel)
} else { // Setting default values for first session
offset = {
x: 0,
y: 0
}
thisObject.zoomLevel = MIN_ZOOM_LEVEL
thisObject.zoomTargetLevel = MIN_ZOOM_LEVEL
}
}
}