Chromium Code Reviews| Index: chrome/browser/resources/settings/device_page/display_layout.js |
| diff --git a/chrome/browser/resources/settings/device_page/display_layout.js b/chrome/browser/resources/settings/device_page/display_layout.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fbc9f5cc2df984b01a11a39ae129740c3b63d064 |
| --- /dev/null |
| +++ b/chrome/browser/resources/settings/device_page/display_layout.js |
| @@ -0,0 +1,228 @@ |
| +/** |
| + * @fileoverview Description of this file. |
|
michaelpg
2016/06/22 21:57:57
remove
stevenjb
2016/06/22 23:38:52
Done.
|
| + */ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * @fileoverview |
| + * 'display-layout' presents a visual representaiton of the layout of one or |
|
michaelpg
2016/06/22 21:57:58
representation
stevenjb
2016/06/22 23:38:52
Done.
|
| + * more displays and allows them to be arranged. |
| + * |
| + * @group Chrome Settings Elements |
|
michaelpg
2016/06/22 21:57:57
remove
stevenjb
2016/06/22 23:38:52
Done.
|
| + */ |
| + |
| +(function() { |
| + |
| +/** @const {number} */ var MIN_VISUAL_SCALE = .01; |
| + |
| +Polymer({ |
| + is: 'display-layout', |
| + |
| + behaviors: [ |
| + Polymer.IronResizableBehavior, |
| + ], |
| + |
| + properties: { |
| + /** |
| + * Array of displays. |
| + * @type {!Array<!chrome.system.display.DisplayUnitInfo>} |
| + */ |
| + displays: Array, |
| + |
| + /** |
| + * Array of display layouts. |
| + * @type {!Array<!chrome.system.display.DisplayLayout>} |
| + */ |
| + layouts: Array, |
| + |
| + /** @type {!chrome.system.display.DisplayUnitInfo|undefined} */ |
| + selectedDisplay: Object, |
| + |
| + /** |
| + * The ratio of the DisplayUnitInfo bounds to pixels (visual bounds). |
| + * @type {number} |
| + */ |
| + visualScale: 1, |
| + }, |
| + |
| + observers: ['displaysChanged_(displays, layouts)'], |
| + |
| + /** @type {!Object<chrome.system.display.DisplayUnitInfo>} */ |
|
michaelpg
2016/06/22 21:57:57
s/type/private here & below
stevenjb
2016/06/22 23:38:52
Done.
|
| + displayMap_: {}, |
| + |
| + /** @type {!Object<chrome.system.display.DisplayLayout>} */ |
| + layoutMap_: {}, |
| + |
| + /** @type {!Object<chrome.system.display.Bounds>} */ |
| + boundsMap_: {}, |
| + |
| + /** @type {!{left: number, top: number}} */ |
| + visualOffset_: {left: 0, top: 0}, |
| + |
| + /** @override */ |
| + attached: function() { |
| + // TODO(stevenjb): Remove retry once fixed: |
| + // https://github.com/Polymer/polymer/issues/3629 |
| + var self = this; |
| + var retry = 100; // ms |
| + function tryCalcDisplayArea() { |
| + if (!self.calculateDisplayArea_()) |
| + setTimeout(tryCalcDisplayArea, retry); |
| + } |
| + tryCalcDisplayArea(); |
| + }, |
| + |
| + /** @private */ |
| + displaysChanged_: function(displays, layouts) { |
| + this.displayMap_ = {}; |
| + for (let display of this.displays) |
| + this.displayMap_[display.id] = display; |
| + |
| + this.layoutMap_ = {}; |
| + for (var layout of this.layouts) |
|
michaelpg
2016/06/22 21:57:57
let, for consistency?
stevenjb
2016/06/22 23:38:52
Done.
|
| + this.layoutMap_[layout.id] = layout; |
| + |
| + this.boundsMap_ = {}; |
| + for (let display of this.displays) |
| + this.calcDisplayBounds_(display); |
| + |
| + this.calculateDisplayArea_(); |
| + }, |
| + |
| + /** |
| + * Calculates the display area offset and scale. |
| + * @return {boolean} Whether the calculation was successful. |
| + * @private |
| + */ |
| + calculateDisplayArea_() { |
|
michaelpg
2016/06/22 21:57:58
to clarify: is the "display area" something to do
stevenjb
2016/06/22 23:38:52
Renamed calculateVisualScale and tried to improve
|
| + var displayAreaDiv = this.$.displayArea; |
| + if (!displayAreaDiv || !displayAreaDiv.offsetWidth || !this.displays) |
| + return false; |
| + |
| + var maxWidth = 0; |
| + var maxHeight = 0; |
| + var boundingBox = {left: 0, right: 0, top: 0, bottom: 0}; |
|
michaelpg
2016/06/22 21:57:58
The bounding box of what?
stevenjb
2016/06/22 23:38:52
Renamed displayInfoBoundingBox (a box bounding all
|
| + |
| + for (var display of this.displays) { |
| + var bounds = this.boundsMap_[display.id]; |
| + boundingBox.left = Math.min(boundingBox.left, bounds.left); |
|
michaelpg
2016/06/22 21:57:58
this ensures boundingBox.left is always 0 or less,
stevenjb
2016/06/22 23:38:52
Good catch. In practice the primary display boundi
|
| + boundingBox.right = |
| + Math.max(boundingBox.right, bounds.left + bounds.width); |
| + boundingBox.top = Math.min(boundingBox.top, bounds.top); |
| + boundingBox.bottom = |
| + Math.max(boundingBox.bottom, bounds.top + bounds.height); |
| + maxWidth = Math.max(maxWidth, bounds.width); |
| + maxHeight = Math.max(maxHeight, bounds.height); |
| + } |
| + |
| + // Create a margin around the bounding box equal to the size of the |
| + // largest display. |
| + var areaWidth = boundingBox.right - boundingBox.left + maxWidth * 2; |
| + var areaHeight = boundingBox.bottom - boundingBox.top + maxHeight * 2; |
| + |
| + // Calculate the scale. |
| + var horizontalScale = displayAreaDiv.offsetWidth / areaWidth; |
| + var verticalScale = displayAreaDiv.offsetHeight / areaHeight; |
| + var scale = Math.min(horizontalScale, verticalScale); |
| + |
| + // Calculate the offset. |
| + this.visualOffset_.left = (-boundingBox.left + maxWidth) * scale; |
| + this.visualOffset_.top = (-boundingBox.top + maxHeight) * scale; |
| + |
| + // Update the scale which will trigger calls to getDivStyle_. |
| + this.visualScale = Math.max(MIN_VISUAL_SCALE, scale); |
| + |
| + return true; |
| + }, |
| + |
| + /** |
| + * @param {!chrome.system.display.DisplayUnitInfo} display |
| + * @param {number} visualScale |
| + * @return {string} The style string for the div. |
| + * @private |
| + */ |
| + getDivStyle_: function(display, visualScale) { |
| + /** @const {number} */ var BORDER = 2; |
| + var bounds = this.boundsMap_[display.id]; |
| + var height = Math.round(bounds.height * this.visualScale) - BORDER * 2; |
| + var width = Math.round(bounds.width * this.visualScale) - BORDER * 2; |
| + var left = |
| + this.visualOffset_.left + Math.round(bounds.left * this.visualScale); |
| + var top = |
| + this.visualOffset_.top + Math.round(bounds.top * this.visualScale); |
| + var style = 'height:' + height + 'px;' + 'width:' + width + 'px;' + |
| + 'left:' + left + 'px;' + 'top:' + top + 'px;'; |
| + return style; |
| + }, |
| + |
| + /** |
| + * @param {!chrome.system.display.DisplayUnitInfo} display |
| + * @param {!chrome.system.display.DisplayUnitInfo} selectedDisplay |
| + * @return {boolean} |
| + * @private |
| + */ |
| + isSelected_: function(display, selectedDisplay) { |
| + return display.id == selectedDisplay.id; |
| + }, |
| + |
| + /** |
| + * @param {!{model: !{index: number}, target: !PaperButtonElement}} e |
| + * @private |
| + */ |
| + onSelectDisplayTap_: function(e) { |
| + this.fire('select-display', e.model.index); |
| + }, |
| + |
| + /** |
| + * Recursively calculate the bounds of a display relative to its parents. |
| + * Caches the display bounds so that parent bounds are only calculated once. |
| + * TODO(stevenjb): Move this function and the maps it requires to a separate |
| + * behavior which will include snapping and collisions. |
| + * @param {!chrome.system.display.DisplayUnitInfo} display |
| + * @return {!chrome.system.display.Bounds} |
| + * @private |
| + */ |
| + calcDisplayBounds_: function(display) { |
| + var left, top; |
| + if (display.isPrimary) { |
| + left = -display.bounds.width / 2; |
| + top = -display.bounds.height / 2; |
| + } else { |
| + var layout = this.layoutMap_[display.id]; |
| + var parentDisplay = this.displayMap_[layout.parentId]; |
| + var parentBounds; |
| + if (parentDisplay.id in this.boundsMap_) |
| + parentBounds = this.boundsMap_[parentDisplay.id]; |
| + else |
| + parentBounds = this.calcDisplayBounds_(parentDisplay); |
| + left = parentBounds.left; |
| + top = parentBounds.top; |
| + switch (layout.position) { |
| + case chrome.system.display.LayoutPosition.TOP: |
| + top -= display.bounds.height; |
| + break; |
| + case chrome.system.display.LayoutPosition.RIGHT: |
| + left += parentBounds.width; |
| + break; |
| + case chrome.system.display.LayoutPosition.BOTTOM: |
| + top += parentBounds.height; |
| + break; |
| + case chrome.system.display.LayoutPosition.LEFT: |
| + left -= display.bounds.height; |
| + break; |
| + } |
| + } |
| + var result = { |
| + left: left, |
| + top: top, |
| + width: display.bounds.width, |
| + height: display.bounds.height |
| + }; |
| + this.boundsMap_[display.id] = result; |
| + return result; |
| + } |
| +}); |
| + |
| +})(); |