graceguo-supercat commented on a change in pull request #4839: Dashboard 
builder: fixed 1st round comments
URL: 
https://github.com/apache/incubator-superset/pull/4839#discussion_r182885909
 
 

 ##########
 File path: 
superset/assets/javascripts/dashboard/util/dashboardLayoutConverter.js
 ##########
 @@ -0,0 +1,331 @@
+import {
+  ROW_TYPE,
+  COLUMN_TYPE,
+  CHART_TYPE,
+  DASHBOARD_HEADER_TYPE,
+  DASHBOARD_ROOT_TYPE,
+  DASHBOARD_GRID_TYPE,
+} from '../v2/util/componentTypes';
+import {
+  DASHBOARD_GRID_ID,
+  DASHBOARD_HEADER_ID,
+  DASHBOARD_ROOT_ID,
+} from '../v2/util/constants';
+
+const MAX_RECURSIVE_LEVEL = 6;
+const GRID_RATIO = 4;
+const ROW_HEIGHT = 8;
+const generateId = function() {
+  let componentId = 1;
+  return () => (componentId++);
+}();
+
+/**
+ *
+ * @param positions: single array of slices
+ * @returns boundary object {top: number, bottom: number, left: number, right: 
number}
+ */
+function getBoundary(positions) {
+  let top = Number.MAX_VALUE, bottom = 0,
+    left = Number.MAX_VALUE, right = 1;
+  positions.forEach(item => {
+    const { row, col, size_x, size_y } = item;
+    if (row <= top) top = row;
+    if (col <= left ) left = col;
+    if (bottom <= row + size_y) bottom = row + size_y;
+    if (right <= col + size_x) right = col + size_x;
+  });
+
+  return {
+    top,
+    bottom,
+    left,
+    right
+  };
+}
+
+function getRowContainer() {
+  const id = 'DASHBOARD_ROW_TYPE-' + generateId();
+  return {
+    version: 'v2',
+    type: ROW_TYPE,
+    id,
+    children: [],
+    meta: {
+      background: 'BACKGROUND_TRANSPARENT',
+    },
+  };
+}
+
+function getColContainer() {
+  const id = 'DASHBOARD_COLUMN_TYPE-' + generateId();
+  return {
+    version: 'v2',
+    type: COLUMN_TYPE,
+    id,
+    children: [],
+    meta: {
+      background: 'BACKGROUND_TRANSPARENT',
+    },
+  };
+}
+
+function getChartHolder(item) {
+  const { row, col, size_x, size_y, slice_id } = item;
+  const converted = {
+    row: Math.round(row / GRID_RATIO),
+    col: Math.floor((col - 1) / GRID_RATIO) + 1,
+    size_x: Math.max(1, Math.floor(size_x / GRID_RATIO)),
+    size_y: Math.max(1, Math.round(size_y / GRID_RATIO)),
+    slice_id,
+  };
+
+  return {
+    version: 'v2',
+    type: CHART_TYPE,
+    id: 'DASHBOARD_CHART_TYPE-' + generateId(),
+    children: [],
+    meta: {
+      width: converted.size_x,
+      height: Math.round(converted.size_y * 100 / ROW_HEIGHT ),
+      chartId: slice_id,
+    },
+  };
+}
+
+function getChildrenMax(items, attr, layout) {
+  return Math.max.apply(null, items.map(child => {
+    return layout[child].meta[attr];
+  }));
+}
+
+function getChildrenSum(items, attr, layout) {
+  return items.reduce((preValue, child) => {
+    return preValue + layout[child].meta[attr];
+  }, 0);
+}
+
+function sortByRowId(item1, item2) {
+  return item1.row - item2.row;
+}
+
+function sortByColId(item1, item2) {
+  return item1.col - item2.col;
+}
+
+function hasOverlap(positions, xAxis = true) {
+  return positions.slice()
+    .sort(!!xAxis ? sortByColId : sortByRowId)
+    .some((item, index, arr) => {
+      if (index === arr.length - 1) {
+        return false;
+      }
+
+      if (!!xAxis) {
+        return (item.col + item.size_x) > arr[index + 1].col;
+      } else {
+        return (item.row + item.size_y) > arr[index + 1].row;
+      }
+    });
+}
+
+function doConvert(positions, level, parent, root) {
+  if (positions.length === 0) {
+    return;
+  }
+
+  if (positions.length === 1 || level >= MAX_RECURSIVE_LEVEL) {
+    // special treatment for single chart dash, always wrap chart inside a row
+    if (parent.type === 'DASHBOARD_GRID_TYPE') {
+      const rowContainer = getRowContainer();
+      root[rowContainer.id] = rowContainer;
+      parent.children.push(rowContainer.id);
+      parent = rowContainer;
+    }
+
+    const chartHolder = getChartHolder(positions[0]);
+    root[chartHolder.id] = chartHolder;
+    parent.children.push(chartHolder.id);
+    return;
+  }
+
+  let currentItems = positions.slice();
+  const { top, bottom, left, right } = getBoundary(positions);
+  // find row dividers
+  const layers = [];
+  let currentRow = top + 1;
+  while (currentItems.length && currentRow <= bottom) {
+    const upper = [],
+      lower = [];
+
+    const isRowDivider = currentItems.every(item => {
+      const { row, col, size_x, size_y } = item;
+      if (row + size_y <= currentRow) {
+        lower.push(item);
+        return true;
+      } else if (row >= currentRow) {
+        upper.push(item);
+        return true;
+      } else {
+        return false;
+      }
+    });
+
+    if (isRowDivider) {
+      currentItems = upper.slice();
+      layers.push(lower);
+    }
+    currentRow++;
+  }
+
+  layers.forEach((layer) => {
+    if (layer.length === 0) {
+      return;
+    }
+
+    if (layer.length === 1) {
+      const chartHolder = getChartHolder(layer[0]);
+      root[chartHolder.id] = chartHolder;
+      parent.children.push(chartHolder.id);
+      return;
+    }
+
+    // create a new row
+    const rowContainer = getRowContainer();
+    root[rowContainer.id] = rowContainer;
+    parent.children.push(rowContainer.id);
+
+    currentItems = layer.slice();
+    if (!hasOverlap(currentItems)) {
+      currentItems.sort(sortByColId).forEach(item => {
+        const chartHolder = getChartHolder(item);
+        root[chartHolder.id] = chartHolder;
+        rowContainer.children.push(chartHolder.id);
+      });
+    } else {
+      // find col dividers for each layer
+      let currentCol = left + 1;
+      while (currentItems.length && currentCol <= right) {
+        const upper = [],
+          lower = [];
+
+        const isColDivider = currentItems.every(item => {
+          const { row, col, size_x, size_y } = item;
+          if (col + size_x <= currentCol) {
+            lower.push(item);
+            return true;
+          } else if (col >= currentCol) {
+            upper.push(item);
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        if (isColDivider) {
+          if (lower.length === 1) {
+            const chartHolder = getChartHolder(lower[0]);
+            root[chartHolder.id] = chartHolder;
+            rowContainer.children.push(chartHolder.id);
+          } else {
+            // create a new column
+            const colContainer = getColContainer();
+            root[colContainer.id] = colContainer;
+            rowContainer.children.push(colContainer.id);
+
+            if (!hasOverlap(lower, false)) {
+              lower.sort(sortByRowId).forEach(item => {
+                const chartHolder = getChartHolder(item);
+                root[chartHolder.id] = chartHolder;
+                colContainer.children.push(chartHolder.id);
+              });
+            } else {
+              doConvert(lower, level+2, colContainer, root);
+            }
+
+            // add col meta
+            colContainer.meta.width = getChildrenMax(colContainer.children, 
'width', root);
+            colContainer.meta.height = getChildrenSum(colContainer.children, 
'height', root);
 
 Review comment:
   i removed `height` calculation from row and column. width might be used by 
row and column that are nested in column. but at the end of function i remove 
row's meta.width.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to