diff --git a/res/app/components/stf/screen/scaling/scaling-service.js b/res/app/components/stf/screen/scaling/scaling-service.js index ed4d3b52..d0cb6082 100644 --- a/res/app/components/stf/screen/scaling/scaling-service.js +++ b/res/app/components/stf/screen/scaling/scaling-service.js @@ -5,17 +5,87 @@ module.exports = function ScalingServiceFactory() { scalingService.coordinator = function (realWidth, realHeight) { var realRatio = realWidth / realHeight + /** + * Rotation affects the screen as follows: + * + * 0deg + * |------| + * | MENU | + * |------| + * --> | | --| + * | | | v + * | | + * | | + * |------| + * |----|-| |-|----| + * |----|M| | |----| + * |----|E| | |----| + * 90deg |----|N| |U|----| 270deg + * |----|U| |N|----| + * |----| | |E|----| + * |----| | |M|----| + * |----|-| |-|----| + * |------| + * ^ | | | + * |-- | | <-- + * | | + * | | + * |------| + * | UNEM | + * |------| + * 180deg + * + * Which leads to the following mapping: + * + * |--------------|------|---------|---------|---------| + * | | 0deg | 90deg | 180deg | 270deg | + * |--------------|------|---------|---------|---------| + * | CSS rotate() | 0deg | -90deg | -180deg | 90deg | + * | bounding w | w | h | w | h | + * | bounding h | h | w | h | w | + * | pos x | x | h-y | w-x | y | + * | pos y | y | x | h-y | x | + * |--------------|------|---------|---------|---------| + */ return { - coords: function (width, height, x, y) { - var ratio = width / height - , scaledValue + coords: function (boundingW, boundingH, relX, relY, rotation) { + var w, h, x, y, ratio, scaledValue + + switch (rotation) { + case 0: + w = boundingW + h = boundingH + x = relX + y = relY + break + case 90: + w = boundingH + h = boundingW + x = boundingH - relY + y = relX + break + case 180: + w = boundingW + h = boundingH + x = boundingW - relX + y = boundingH - relY + break + case 270: + w = boundingH + h = boundingW + x = relY + y = relX + break + } + + ratio = w / h if (realRatio > ratio) { // covers the area horizontally - scaledValue = width / realRatio + scaledValue = w / realRatio // adjust y to start from the scaled top edge - y -= (height - scaledValue) / 2 + y -= (h - scaledValue) / 2 // not touching the screen, but we want to trigger certain events // (like touchup) anyway, so let's do it on the edges. @@ -30,18 +100,18 @@ module.exports = function ScalingServiceFactory() { if (x < 0) { x = 0 } - else if (x > width) { - x = width + else if (x > w) { + x = w } - height = scaledValue + h = scaledValue } else { // covers the area vertically - scaledValue = height * realRatio + scaledValue = h * realRatio // adjust x to start from the scaled left edge - x -= (width - scaledValue) / 2 + x -= (w - scaledValue) / 2 // not touching the screen, but we want to trigger certain events // (like touchup) anyway, so let's do it on the edges. @@ -56,16 +126,16 @@ module.exports = function ScalingServiceFactory() { if (y < 0) { y = 0 } - else if (y > height) { - y = height + else if (y > h) { + y = h } - width = scaledValue + w = scaledValue } return { - xP: x / width - , yP: y / height + xP: x / w + , yP: y / h } } , size: function (width, height) { @@ -101,20 +171,35 @@ module.exports = function ScalingServiceFactory() { , height: height } } - , projectedSize: function (width, height) { - var ratio = width / height + , projectedSize: function (boundingW, boundingH, rotation) { + var w, h + + switch (rotation) { + case 0: + case 180: + w = boundingW + h = boundingH + break + case 90: + case 270: + w = boundingH + h = boundingW + break + } + + var ratio = w / h if (realRatio > ratio) { // covers the area horizontally - height = Math.floor(width / realRatio) + h = Math.floor(w / realRatio) } else { - width = Math.floor(height * realRatio) + w = Math.floor(h * realRatio) } return { - width: width - , height: height + width: w + , height: h } } } diff --git a/res/app/components/stf/screen/screen-directive.js b/res/app/components/stf/screen/screen-directive.js index ce23b343..be26bf36 100644 --- a/res/app/components/stf/screen/screen-directive.js +++ b/res/app/components/stf/screen/screen-directive.js @@ -13,23 +13,26 @@ module.exports = function DeviceScreenDirective( , imageRender = new FastImageRender(canvas, {render: 'canvas'}) , finger = element.find('span') , input = element.find('textarea') - , displayWidth = 0 // TODO: cache inside FastImageRender? - , displayHeight = 0 - , cachedDisplayWidth = 0 - , cachedDisplayHeight = 0 + , boundingWidth = 0 // TODO: cache inside FastImageRender? + , boundingHeight = 0 + , cachedBoundingWidth = 0 + , cachedBoundingHeight = 0 , cachedImageWidth = 0 , cachedImageHeight = 0 + , cachedRotation = 0 + , rotation = 0 , loading = false , scaler , seq = 0 , cssTransform = VendorUtil.style(['transform', 'webkitTransform']) - scope.$on('panelsResized', updateDisplaySize) + scope.$on('panelsResized', updateBounds) function sendTouch(type, e) { var x = e.offsetX || e.layerX || 0 , y = e.offsetY || e.layerY || 0 - , scaled = scaler.coords(displayWidth, displayHeight, x, y) + , r = scope.device.display.orientation + , scaled = scaler.coords(boundingWidth, boundingHeight, x, y, r) finger[0].style[cssTransform] = 'translate3d(' + x + 'px,' + y + 'px,0)' @@ -49,12 +52,12 @@ module.exports = function DeviceScreenDirective( seq = 0 } - function updateDisplaySize() { - displayWidth = element[0].offsetWidth - displayHeight = element[0].offsetHeight + function updateBounds() { + boundingWidth = element[0].offsetWidth + boundingHeight = element[0].offsetHeight // Developer error, let's try to reduce debug time - if (!displayWidth || !displayHeight) { + if (!boundingWidth || !boundingHeight) { throw new Error( 'Unable to update display size; container must have dimensions' ) @@ -102,8 +105,8 @@ module.exports = function DeviceScreenDirective( if (!loading && scope.canView && scope.showScreen && scope.device) { loading = true imageRender.load(scope.device.display.url + - '?width=' + displayWidth + - '&height=' + displayHeight + + '?width=' + boundingWidth + + '&height=' + boundingHeight + '&time=' + Date.now() ) } @@ -121,23 +124,49 @@ module.exports = function DeviceScreenDirective( if (scope.canView && scope.showScreen) { // Check to set the size only if updated - if (cachedDisplayWidth !== displayWidth || - cachedDisplayHeight !== displayHeight || + if (cachedBoundingWidth !== boundingWidth || + cachedBoundingHeight !== boundingHeight || cachedImageWidth !== image.width || - cachedImageHeight !== image.height) { + cachedImageHeight !== image.height || + cachedRotation !== rotation) { - cachedDisplayWidth = displayWidth - cachedDisplayHeight = displayHeight + cachedBoundingWidth = boundingWidth + cachedBoundingHeight = boundingHeight cachedImageWidth = image.width cachedImageHeight = image.height + cachedRotation = rotation + imageRender.canvasWidth = cachedImageWidth imageRender.canvasHeight = cachedImageHeight - var size = scaler.projectedSize(displayWidth, displayHeight) + var size = scaler.projectedSize( + boundingWidth + , boundingHeight + , rotation + ) + imageRender.canvasStyleWidth = size.width imageRender.canvasStyleHeight = size.height + + // @todo Make sure that each position is able to rotate smoothly + // to the next one. This current setup doesn't work if rotation + // changes from 180 to 270 (it will do a reverse rotation). + switch (rotation) { + case 0: + canvas.style[cssTransform] = 'rotate(0deg)' + break + case 90: + canvas.style[cssTransform] = 'rotate(-90deg)' + break + case 180: + canvas.style[cssTransform] = 'rotate(-180deg)' + break + case 270: + canvas.style[cssTransform] = 'rotate(90deg)' + break + } } imageRender.draw(image) @@ -164,7 +193,7 @@ module.exports = function DeviceScreenDirective( }) } - updateDisplaySize() + updateBounds() maybeLoadScreen() input.bind('keydown', keydownListener) @@ -212,6 +241,10 @@ module.exports = function DeviceScreenDirective( } }) + scope.$watch('device.display.orientation', function(r) { + rotation = r || 0 + }) + scope.$on('$destroy', off) } } diff --git a/res/app/control-panes/device-control/device-control.css b/res/app/control-panes/device-control/device-control.css index cfe2f48f..7333f202 100644 --- a/res/app/control-panes/device-control/device-control.css +++ b/res/app/control-panes/device-control/device-control.css @@ -11,6 +11,9 @@ device-screen { } device-screen canvas { + -webkit-transition: -webkit-transform 250ms ease-in-out; + -webkit-transform-origin: 50% 50%; + -webkit-transform: rotate(0deg); position: absolute; margin: auto; top: 0;