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:
jdescottes 2013-11-01 23:11:11 +01:00
parent 68edbe62c7
commit bd99027852
11 changed files with 158 additions and 19 deletions

8
css/minimap.css Normal file
View 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;
}

View File

@ -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;
}
/**

View File

@ -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>

View File

@ -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();

View File

@ -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_();
};
})();

View 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;
};
})();

View File

@ -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';};

View File

@ -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);
});
};

View File

@ -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
View 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);
}
};
})();

View File

@ -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",