Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Unified Diff: chrome/browser/resources/settings/device_page/display_layout.js

Issue 2084673003: MD Settings: Add display layout (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@issue_547080_display_settings6
Patch Set: Feedback Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..0ab8d7860fb07e6ceb0cdc2fbd8bb973db775e2a
--- /dev/null
+++ b/chrome/browser/resources/settings/device_page/display_layout.js
@@ -0,0 +1,232 @@
+// 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 representation of the layout of one or
+ * more displays and allows them to be arranged.
+ */
+
+(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 display area div (in px) to DisplayUnitInfo.bounds.
+ * @type {number}
+ */
+ visualScale: 1,
+ },
+
+ observers: ['displaysChanged_(displays, layouts)'],
+
+ /** @private {!Object<chrome.system.display.DisplayUnitInfo>} */
+ displayMap_: {},
+
+ /** @private {!Object<chrome.system.display.DisplayLayout>} */
+ layoutMap_: {},
+
+ /** @private {!Object<chrome.system.display.Bounds>} */
+ boundsMap_: {},
+
+ /** @private {!{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 tryCalcVisualScale() {
+ if (!self.calculateVisualScale_())
+ setTimeout(tryCalcVisualScale, retry);
+ }
+ tryCalcVisualScale();
+ },
+
+ /** @private */
+ displaysChanged_: function(displays, layouts) {
+ this.displayMap_ = {};
+ for (let display of this.displays)
+ this.displayMap_[display.id] = display;
+
+ this.layoutMap_ = {};
+ for (let layout of this.layouts)
+ this.layoutMap_[layout.id] = layout;
+
+ this.boundsMap_ = {};
+ for (let display of this.displays)
+ this.calcDisplayBounds_(display);
+
+ this.calculateVisualScale_();
+ },
+
+ /**
+ * Calculates the visual offset and scale for the display area
+ * (i.e. the ratio of the display area div size to the area required to
+ * contain the DisplayUnitInfo bounding boxes).
+ * @return {boolean} Whether the calculation was successful.
+ * @private
+ */
+ calculateVisualScale_() {
+ var displayAreaDiv = this.$.displayArea;
+ if (!displayAreaDiv || !displayAreaDiv.offsetWidth || !this.displays)
+ return false;
+
+ var maxWidth = 0;
+ var maxHeight = 0;
+ var displayInfoBoundingBox =
+ {left: Number.MAX_VALUE, right: 0, top: Number.MAX_VALUE, bottom: 0};
michaelpg 2016/06/23 04:29:35 Normally the origin (0, 0) is the top-left, and th
stevenjb 2016/06/23 19:11:01 The intention is that these will be immediately ov
michaelpg 2016/06/24 20:25:10 If you use Array.prototype.reduce you wouldn't hav
stevenjb 2016/06/24 20:59:51 Interesting. I can see how that would be useful, b
+
+ for (let display of this.displays) {
+ var bounds = this.boundsMap_[display.id];
+ displayInfoBoundingBox.left =
+ Math.min(displayInfoBoundingBox.left, bounds.left);
+ displayInfoBoundingBox.right =
+ Math.max(displayInfoBoundingBox.right, bounds.left + bounds.width);
+ displayInfoBoundingBox.top =
+ Math.min(displayInfoBoundingBox.top, bounds.top);
+ displayInfoBoundingBox.bottom =
+ Math.max(displayInfoBoundingBox.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.
michaelpg 2016/06/23 04:29:34 display(s) -- e.g., a landscape display and a port
stevenjb 2016/06/23 19:11:01 Done.
+ var displayInfoBoundsWidth =
+ displayInfoBoundingBox.right - displayInfoBoundingBox.left +
+ maxWidth * 2;
+ var displayInfoBoundsHeight =
+ displayInfoBoundingBox.bottom - displayInfoBoundingBox.top +
+ maxHeight * 2;
+
+ // Calculate the scale.
+ var horizontalScale = displayAreaDiv.offsetWidth / displayInfoBoundsWidth;
+ var verticalScale = displayAreaDiv.offsetHeight / displayInfoBoundsHeight;
+ var scale = Math.min(horizontalScale, verticalScale);
+
+ // Calculate the offset.
+ this.visualOffset_.left = (-displayInfoBoundingBox.left + maxWidth) * scale;
+ this.visualOffset_.top = (-displayInfoBoundingBox.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;
michaelpg 2016/06/23 04:29:35 why 2, when the border with on .display is 1?
stevenjb 2016/06/23 19:11:01 It has a box shadow of width 2. Added a comment.
+ var bounds = this.boundsMap_[display.id];
+ var height = Math.round(bounds.height * this.visualScale) - BORDER * 2;
michaelpg 2016/06/23 04:29:35 I think using box-sizing: border-box on these divs
stevenjb 2016/06/23 19:11:01 Alas, your newfangled CSS property doesn't appear
+ var width = Math.round(bounds.width * this.visualScale) - BORDER * 2;
+ var left =
+ this.visualOffset_.left + Math.round(bounds.left * this.visualScale);
michaelpg 2016/06/23 04:29:34 why round the 2nd term but not the offset?
stevenjb 2016/06/23 19:11:01 Good catch. Fixed.
+ var top =
+ this.visualOffset_.top + Math.round(bounds.top * this.visualScale);
+ var style = 'height:' + height + 'px;' + 'width:' + width + 'px;' +
michaelpg 2016/06/23 04:29:35 i think this is a great use case for es6 template
stevenjb 2016/06/23 19:11:01 Cute. Closure is fine with it. Done.
+ '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
michaelpg 2016/06/23 04:29:35 meh, remove unused target property info
stevenjb 2016/06/23 19:11:01 Done.
+ * @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;
+ }
+});
+
+})();

Powered by Google App Engine
This is Rietveld 408576698