class Position { int x = 0; int y = 0; } class Delta { int dx = 0; int dy = 0; } class RectArea { Position position = new Position(); Delta delta = new Delta(); color fillColor; int opacity; RectArea(color fillColor, int opacity) { this.fillColor = fillColor; this.opacity = opacity; } void setSize(int dx, int dy) { delta.dx = dx; delta.dy = dy; } boolean hitTest(int posX, int posY) { return posX >= position.x && posX <= (position.x + delta.dx) && posY >= position.y && posY <= (position.y + delta.dy); } void initialize() { placeAtCenter(this); } void setX(int x) { position.x = x; } void moveX(int dx) { position.x += dx; } int maybeMoveX(int dx) { return position.x + dx; } void paint() { fill(fillColor, opacity); rect(position.x, position.y, delta.dx, delta.dy); } } void placeAtCenter(RectArea area) { area.position.x = height / 2 - area.delta.dx / 2; area.position.y = width / 2 - area.delta.dy / 2; } boolean drag = false; boolean inDrag = false; int lastMouseX = 0; int canvasX = 400; int canvasY = 400; RectArea viewableArea = new RectArea(#93BAF7, 200); RectArea backgroundArea = new RectArea(#CE7BCE, 255); int scaleBy = 0; int excessXs = 0; int scrollEdgeX1_b = 0; int scrollEdgeX2_b = 0; int scrollEdgeX1_v = 0; int scrollEdgeX2_v = 0; void setup() { size(canvasX, canvasY); background(0); noStroke(); frameRate(25); lastMouseX = mouseX; viewableArea.setSize(100, 200); backgroundArea.setSize(250, 200); backgroundArea.initialize(); backgroundArea.paint(); viewableArea.initialize(); viewableArea.paint(); float vdx = viewableArea.delta.dx; float bdx = backgroundArea.delta.dx; int slack = (int)((3*vdx - bdx)/2); scaleBy = (int)(vdx / slack); println(scaleBy); scrollEdgeX1_v = viewableArea.position.x - viewableArea.delta.dx; scrollEdgeX2_v = viewableArea.position.x + viewableArea.delta.dx; scrollEdgeX1_b = scrollEdgeX1_v; scrollEdgeX2_b = backgroundArea.position.x + slack; } void putAtEdge(RectArea r, int x) { r.setX(x); inDrag = false; } void draw() { if (drag) { background(0); backgroundArea.paint(); int dx = -1 * (lastMouseX - mouseX); boolean resetDrag = false; if ( viewableArea.maybeMoveX(dx) < scrollEdgeX1_v ) { putAtEdge(viewableArea, scrollEdgeX1_v); putAtEdge(backgroundArea, scrollEdgeX1_b); } else if ( viewableArea.maybeMoveX(dx) > scrollEdgeX2_v ) { putAtEdge(viewableArea, scrollEdgeX2_v); putAtEdge(backgroundArea, scrollEdgeX2_b); } else { viewableArea.moveX(dx); backgroundArea.moveX((dx + excessXs) / scaleBy); excessXs = (dx + excessXs) % scaleBy; } viewableArea.paint(); } lastMouseX = mouseX; } void mouseDragged() { if (inDrag) return; drag = viewableArea.hitTest(mouseX, mouseY); if (drag) inDrag = true; } void mouseReleased() { inDrag = false; drag = false; }