mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
feature : zoom
- Added MinimapController that displays a frame on the animated preview when zoomed in - Added bounds for the offset to make sure it doesn't go crazy - Added new utility Math.js with a minmax function - TODO : the minimap controller has a lot of dependencies, see if could be cleaned up - TODO : DrawingController knows the size of the picture it has to render only indirectly, which makes it hard in some cases (such as boundary checking performed during setOffset)
This commit is contained in:
parent
68edbe62c7
commit
bd99027852
8
css/minimap.css
Normal file
8
css/minimap.css
Normal file
@ -0,0 +1,8 @@
|
||||
.minimap-crop-frame {
|
||||
position:absolute;
|
||||
border:1px solid red;
|
||||
z-index:9999;
|
||||
box-sizing : border-box;
|
||||
-moz-box-sizing : border-box;
|
||||
cursor : pointer;
|
||||
}
|
@ -174,6 +174,10 @@ body {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.preview-container .canvas-container {
|
||||
overflow : hidden;
|
||||
}
|
||||
|
||||
.preview-container canvas {
|
||||
border : 0px Solid transparent;
|
||||
}
|
||||
@ -189,6 +193,7 @@ body {
|
||||
|
||||
.range-fps {
|
||||
overflow: hidden;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-tooltip-custom.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/preview-film-section.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/minimap.css">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="js/lib/iframeLoader.js"></script>
|
||||
|
@ -27,6 +27,9 @@
|
||||
this.animationController = new pskl.controller.AnimatedPreviewController(this.piskelController, $('#preview-canvas-container'));
|
||||
this.animationController.init();
|
||||
|
||||
this.minimapController = new pskl.controller.MinimapController(this.piskelController, this.animationController, this.drawingController, $('#preview-canvas-container'));
|
||||
this.minimapController.init();
|
||||
|
||||
this.previewsController = new pskl.controller.PreviewFilmController(this.piskelController, $('#preview-list'));
|
||||
this.previewsController.init();
|
||||
|
||||
|
@ -82,6 +82,7 @@
|
||||
this.container.mousedown($.proxy(this.onMousedown_, this));
|
||||
this.container.mousemove($.proxy(this.onMousemove_, this));
|
||||
this.container.on('mousewheel', $.proxy(this.onMousewheel_, this));
|
||||
this.container.on('wheel', $.proxy(this.onMousewheel_, this));
|
||||
|
||||
body.mouseup($.proxy(this.onMouseup_, this));
|
||||
|
||||
@ -175,13 +176,14 @@
|
||||
|
||||
ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) {
|
||||
var event = jQueryEvent.originalEvent;
|
||||
var delta = event.wheelDeltaY;
|
||||
var delta = event.wheelDeltaY || (-2 * event.deltaY);
|
||||
var currentZoom = this.renderer.getZoom();
|
||||
if (delta > 0) {
|
||||
this.compositeRenderer.setZoom(currentZoom + 1);
|
||||
} else if (delta < 0) {
|
||||
this.compositeRenderer.setZoom(currentZoom - 1);
|
||||
}
|
||||
pskl.app.minimapController.onDrawingControllerMove_();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -308,7 +310,12 @@
|
||||
});
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.moveOffset = function (xOffset, yOffset) {
|
||||
this.compositeRenderer.moveOffset(xOffset, yOffset);
|
||||
ns.DrawingController.prototype.getRenderer = function () {
|
||||
return this.compositeRenderer;
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.setOffset = function (x, y) {
|
||||
this.compositeRenderer.setOffset(x, y);
|
||||
pskl.app.minimapController.onDrawingControllerMove_();
|
||||
};
|
||||
})();
|
85
js/controller/MinimapController.js
Normal file
85
js/controller/MinimapController.js
Normal file
@ -0,0 +1,85 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.MinimapController = function (piskelController, animationController, drawingController, container) {
|
||||
this.piskelController = piskelController;
|
||||
this.animationController = animationController;
|
||||
this.drawingController = drawingController;
|
||||
this.container = container;
|
||||
|
||||
this.isClicked = false;
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.init = function () {
|
||||
this.cropFrame = document.createElement('DIV');
|
||||
this.cropFrame.className = 'minimap-crop-frame';
|
||||
this.cropFrame.style.display = 'none';
|
||||
$(this.container).mousedown(this.onMinimapMousedown_.bind(this));
|
||||
$(this.container).mousemove(this.onMinimapMousemove_.bind(this));
|
||||
$(this.container).mouseup(this.onMinimapMouseup_.bind(this));
|
||||
$(this.container).append(this.cropFrame);
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.onDrawingControllerMove_ = function () {
|
||||
var zoomRatio = this.getDrawingAreaZoomRatio_();
|
||||
if (zoomRatio > 1) {
|
||||
this.displayCropFrame_(zoomRatio, this.drawingController.getRenderer().getOffset());
|
||||
} else {
|
||||
this.hideCropFrame_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.displayCropFrame_ = function (ratio, offset) {
|
||||
this.cropFrame.style.display = 'block';
|
||||
this.cropFrame.style.top = (offset.y * this.animationController.renderer.getZoom()) + 'px';
|
||||
this.cropFrame.style.left = (offset.x * this.animationController.renderer.getZoom()) + 'px';
|
||||
var zoomRatio = this.getDrawingAreaZoomRatio_();
|
||||
this.cropFrame.style.width = (this.container.width() / zoomRatio) + 'px';
|
||||
this.cropFrame.style.height = (this.container.height() / zoomRatio) + 'px';
|
||||
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.hideCropFrame_ = function () {
|
||||
this.cropFrame.style.display = 'none';
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.onMinimapMousemove_ = function (evt) {
|
||||
if (this.isClicked) {
|
||||
if (this.getDrawingAreaZoomRatio_() > 1) {
|
||||
var coords = this.getCoordinatesCenteredAround_(evt.clientX, evt.clientY);
|
||||
this.drawingController.setOffset(coords.x, coords.y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.onMinimapMousedown_ = function (evt) {
|
||||
this.isClicked = true;
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.onMinimapMouseup_ = function (evt) {
|
||||
this.isClicked = false;
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.getCoordinatesCenteredAround_ = function (x, y) {
|
||||
var frameCoords = this.animationController.renderer.getCoordinates(x, y);
|
||||
var zoomRatio = this.getDrawingAreaZoomRatio_();
|
||||
var frameWidth = this.piskelController.getCurrentFrame().getWidth();
|
||||
var frameHeight = this.piskelController.getCurrentFrame().getHeight();
|
||||
|
||||
var width = frameWidth / zoomRatio;
|
||||
var height = frameHeight / zoomRatio;
|
||||
|
||||
return {
|
||||
x : frameCoords.x - (width/2),
|
||||
y : frameCoords.y - (height/2)
|
||||
};
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.getDrawingAreaZoomRatio_ = function () {
|
||||
var drawingAreaZoom = this.drawingController.getRenderer().getZoom();
|
||||
var drawingAreaFullHeight = this.piskelController.getCurrentFrame().getHeight() * drawingAreaZoom;
|
||||
var zoomRatio = drawingAreaFullHeight / this.drawingController.getRenderer().getDisplaySize().height;
|
||||
|
||||
return zoomRatio;
|
||||
};
|
||||
})();
|
@ -14,6 +14,7 @@
|
||||
ns.AbstractRenderer.prototype.getZoom = function () {throw 'abstract method should be implemented';};
|
||||
|
||||
ns.AbstractRenderer.prototype.moveOffset = function (x, y) {throw 'abstract method should be implemented';};
|
||||
ns.AbstractRenderer.prototype.setOffset = function (x, y) {throw 'abstract method should be implemented';};
|
||||
ns.AbstractRenderer.prototype.getOffset = function () {throw 'abstract method should be implemented';};
|
||||
|
||||
ns.AbstractRenderer.prototype.setDisplaySize = function (w, h) {throw 'abstract method should be implemented';};
|
||||
|
@ -38,9 +38,15 @@
|
||||
return this.getSampleRenderer_().getDisplaySize();
|
||||
};
|
||||
|
||||
ns.CompositeRenderer.prototype.moveOffset = function (offsetX, offsetY) {
|
||||
ns.CompositeRenderer.prototype.moveOffset = function (x, y) {
|
||||
this.renderers.forEach(function (renderer) {
|
||||
renderer.moveOffset(offsetX, offsetY);
|
||||
renderer.moveOffset(x, y);
|
||||
});
|
||||
};
|
||||
|
||||
ns.CompositeRenderer.prototype.setOffset = function (x, y) {
|
||||
this.renderers.forEach(function (renderer) {
|
||||
renderer.setOffset(x, y);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,17 @@
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.setZoom = function (zoom) {
|
||||
this.zoom = zoom;
|
||||
// back up center coordinates
|
||||
var centerX = this.offset.x + (this.displayWidth/(2*this.zoom));
|
||||
var centerY = this.offset.y + (this.displayHeight/(2*this.zoom));
|
||||
|
||||
this.zoom = Math.max(1, zoom);
|
||||
|
||||
// recenter
|
||||
this.setOffset(
|
||||
centerX - (this.displayWidth/(2*this.zoom)),
|
||||
centerY - (this.displayHeight/(2*this.zoom))
|
||||
);
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.getZoom = function () {
|
||||
@ -108,7 +118,21 @@
|
||||
},
|
||||
|
||||
ns.FrameRenderer.prototype.moveOffset = function (x, y) {
|
||||
this.setOffset_(this.offset.x + x, this.offset.y + y);
|
||||
this.setOffset(this.offset.x + x, this.offset.y + y);
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.setOffset = function (x, y) {
|
||||
// TODO : provide frame size information to the FrameRenderer constructor
|
||||
// here I first need to verify I have a 'canvas' which I can use to infer the frame information
|
||||
// and then perform my boundaries checking. This sucks
|
||||
if (this.canvas) {
|
||||
var maxX = this.canvas.width - (this.displayWidth/this.zoom);
|
||||
x = pskl.utils.Math.minmax(x, 0, maxX);
|
||||
var maxY = this.canvas.height - (this.displayHeight/this.zoom);
|
||||
y = pskl.utils.Math.minmax(y, 0, maxY);
|
||||
}
|
||||
this.offset.x = x;
|
||||
this.offset.y = y;
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.setGridEnabled = function (flag) {
|
||||
@ -135,11 +159,6 @@
|
||||
this.container.append(this.displayCanvas);
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.setOffset_ = function (x, y) {
|
||||
this.offset.x = x;
|
||||
this.offset.y = y;
|
||||
};
|
||||
|
||||
ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) {
|
||||
if(settingName == pskl.UserSettings.SHOW_GRID) {
|
||||
this.setGridEnabled(settingValue);
|
||||
@ -189,13 +208,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.FrameRenderer.prototype.getFramePos_ = function(index) {
|
||||
return index * this.dpi + ((index - 1) * this.gridStrokeWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
9
js/utils/Math.js
Normal file
9
js/utils/Math.js
Normal file
@ -0,0 +1,9 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
ns.Math = {
|
||||
minmax : function (val, min, max) {
|
||||
return Math.max(Math.min(val, max), min);
|
||||
}
|
||||
};
|
||||
})();
|
@ -14,6 +14,7 @@ exports.scripts = [
|
||||
// Libraries
|
||||
"js/utils/core.js",
|
||||
"js/utils/CanvasUtils.js",
|
||||
"js/utils/Math.js",
|
||||
"js/utils/FrameUtils.js",
|
||||
"js/utils/PixelUtils.js",
|
||||
"js/utils/Serializer.js",
|
||||
@ -50,6 +51,7 @@ exports.scripts = [
|
||||
"js/controller/PreviewFilmController.js",
|
||||
"js/controller/LayersListController.js",
|
||||
"js/controller/AnimatedPreviewController.js",
|
||||
"js/controller/MinimapController.js",
|
||||
"js/controller/ToolController.js",
|
||||
"js/controller/PaletteController.js",
|
||||
"js/controller/NotificationController.js",
|
||||
|
Loading…
Reference in New Issue
Block a user