diff --git a/public/app/features/canvas/element.ts b/public/app/features/canvas/element.ts index 90c6d4b650b..7a59e8aa049 100644 --- a/public/app/features/canvas/element.ts +++ b/public/app/features/canvas/element.ts @@ -1,6 +1,6 @@ import { ComponentType } from 'react'; import { RegistryItem } from '@grafana/data'; -import { Anchor, BackgroundConfig, LineConfig, Placement } from './types'; +import { BackgroundConfig, Constraint, LineConfig, Placement } from './types'; import { DimensionContext } from '../dimensions/context'; import { PanelOptionsSupplier } from '@grafana/data/src/panel/PanelPlugin'; @@ -19,7 +19,7 @@ export interface CanvasElementOptions { config?: TConfig; // Standard options available for all elements - anchor?: Anchor; // defaults top, left, width and height + constraint?: Constraint; // defaults vertical - top, horizontal - left placement?: Placement; background?: BackgroundConfig; border?: LineConfig; @@ -29,10 +29,6 @@ export interface CanvasElementProps { // Saved config config: TConfig; - // Calculated position info - width: number; - height: number; - // Raw data data?: TData; } @@ -53,6 +49,6 @@ export interface CanvasElementItem extends RegistryI getNewOptions: (options?: CanvasElementOptions) => Omit, 'type' | 'name'>; - /** Build the configuraiton UI */ + /** Build the configuration UI */ registerOptionsUI?: PanelOptionsSupplier>; } diff --git a/public/app/features/canvas/elements/icon.tsx b/public/app/features/canvas/elements/icon.tsx index 53652474c1e..7a62093dbbb 100644 --- a/public/app/features/canvas/elements/icon.tsx +++ b/public/app/features/canvas/elements/icon.tsx @@ -38,7 +38,7 @@ const svgStrokePathClass = css` `; export function IconDisplay(props: CanvasElementProps) { - const { width, height, data } = props; + const { data } = props; if (!data?.path) { return null; } @@ -59,8 +59,6 @@ export function IconDisplay(props: CanvasElementProps) { @@ -78,6 +76,8 @@ export const iconItem: CanvasElementItem = { placement: { width: 50, height: 50, + top: 0, + left: 0, }, ...options, config: { diff --git a/public/app/features/canvas/runtime/element.tsx b/public/app/features/canvas/runtime/element.tsx index 51e06c08b0d..f8f90561e0a 100644 --- a/public/app/features/canvas/runtime/element.tsx +++ b/public/app/features/canvas/runtime/element.tsx @@ -6,14 +6,13 @@ import { CanvasElementItem, CanvasElementOptions, canvasElementRegistry, - Placement, - Anchor, } from 'app/features/canvas'; import { DimensionContext } from 'app/features/dimensions'; import { notFoundItem } from 'app/features/canvas/elements/notFound'; import { GroupState } from './group'; import { LayerElement } from 'app/core/components/Layers/types'; import { Scene } from './scene'; +import { HorizontalConstraint, Placement, VerticalConstraint } from '../types'; let counter = 0; @@ -28,23 +27,24 @@ export class ElementState implements LayerElement { div?: HTMLDivElement; // Calculated - width = 100; - height = 100; data?: any; // depends on the type - // From options, but always set and always valid - anchor: Anchor; - placement: Placement; - constructor(public item: CanvasElementItem, public options: CanvasElementOptions, public parent?: GroupState) { const fallbackName = `Element ${Date.now()}`; if (!options) { this.options = { type: item.id, name: fallbackName }; } - this.anchor = options.anchor ?? {}; - this.placement = options.placement ?? {}; - options.anchor = this.anchor; - options.placement = this.placement; + + options.constraint = options.constraint ?? { + vertical: VerticalConstraint.Top, + horizontal: HorizontalConstraint.Left, + }; + options.placement = options.placement ?? { width: 100, height: 100, top: 0, left: 0 }; + this.validatePlacement(); + this.sizeStyle = { + ...options.placement, + position: 'absolute', + }; const scene = this.getScene(); if (!options.name) { @@ -72,71 +72,106 @@ export class ElementState implements LayerElement { } validatePlacement() { - const { anchor, placement } = this; - if (!(anchor.left || anchor.right)) { - anchor.left = true; - } - if (!(anchor.top || anchor.bottom)) { - anchor.top = true; + const { constraint, placement } = this.options; + const { vertical, horizontal } = constraint ?? {}; + const updatedPlacement = placement ?? ({} as Placement); + + switch (vertical) { + case VerticalConstraint.Top: + updatedPlacement.top = updatedPlacement.top ?? 0; + updatedPlacement.height = updatedPlacement.height ?? 100; + delete updatedPlacement.bottom; + break; + case VerticalConstraint.Bottom: + updatedPlacement.bottom = updatedPlacement.bottom ?? 0; + updatedPlacement.height = updatedPlacement.height ?? 100; + delete updatedPlacement.top; + break; + case VerticalConstraint.TopBottom: + updatedPlacement.top = updatedPlacement.top ?? 0; + updatedPlacement.bottom = updatedPlacement.bottom ?? 0; + delete updatedPlacement.height; + break; } - const w = placement.width ?? 100; // this.div ? this.div.clientWidth : this.width; - const h = placement.height ?? 100; // this.div ? this.div.clientHeight : this.height; - - if (anchor.top) { - if (!placement.top) { - placement.top = 0; - } - if (anchor.bottom) { - delete placement.height; - } else { - placement.height = h; - delete placement.bottom; - } - } else if (anchor.bottom) { - if (!placement.bottom) { - placement.bottom = 0; - } - placement.height = h; - delete placement.top; + switch (horizontal) { + case HorizontalConstraint.Left: + updatedPlacement.left = updatedPlacement.left ?? 0; + updatedPlacement.width = updatedPlacement.width ?? 100; + delete updatedPlacement.right; + break; + case HorizontalConstraint.Right: + updatedPlacement.right = updatedPlacement.right ?? 0; + updatedPlacement.width = updatedPlacement.width ?? 100; + delete updatedPlacement.left; + break; + case HorizontalConstraint.LeftRight: + updatedPlacement.left = updatedPlacement.left ?? 0; + updatedPlacement.right = updatedPlacement.right ?? 0; + delete updatedPlacement.width; + break; } - if (anchor.left) { - if (!placement.left) { - placement.left = 0; - } - if (anchor.right) { - delete placement.width; - } else { - placement.width = w; - delete placement.right; - } - } else if (anchor.right) { - if (!placement.right) { - placement.right = 0; - } - placement.width = w; - delete placement.left; - } - - this.width = w; - this.height = h; - - this.options.anchor = this.anchor; - this.options.placement = this.placement; + this.options.placement = updatedPlacement; } - // The parent size, need to set our own size based on offsets - updateSize(width: number, height: number) { - this.width = width; - this.height = height; - this.validatePlacement(); + setPlacementFromConstraint() { + const { constraint } = this.options; + const { vertical, horizontal } = constraint ?? {}; - // Update the CSS position + const elementContainer = this.div && this.div.getBoundingClientRect(); + const parentContainer = this.div && this.div.parentElement?.getBoundingClientRect(); + + const relativeTop = + elementContainer && parentContainer ? Math.abs(Math.round(elementContainer.top - parentContainer.top)) : 0; + const relativeBottom = + elementContainer && parentContainer ? Math.abs(Math.round(elementContainer.bottom - parentContainer.bottom)) : 0; + const relativeLeft = + elementContainer && parentContainer ? Math.abs(Math.round(elementContainer.left - parentContainer.left)) : 0; + const relativeRight = + elementContainer && parentContainer ? Math.abs(Math.round(elementContainer.right - parentContainer.right)) : 0; + + const placement = {} as Placement; + + const width = elementContainer?.width ?? 100; + const height = elementContainer?.height ?? 100; + + switch (vertical) { + case VerticalConstraint.Top: + placement.top = relativeTop; + placement.height = height; + break; + case VerticalConstraint.Bottom: + placement.bottom = relativeBottom; + placement.height = height; + break; + case VerticalConstraint.TopBottom: + placement.top = relativeTop; + placement.bottom = relativeBottom; + break; + } + + switch (horizontal) { + case HorizontalConstraint.Left: + placement.left = relativeLeft; + placement.width = width; + break; + case HorizontalConstraint.Right: + placement.right = relativeRight; + placement.width = width; + break; + case HorizontalConstraint.LeftRight: + placement.left = relativeLeft; + placement.right = relativeRight; + break; + } + + this.options.placement = placement; this.sizeStyle = { ...this.options.placement, position: 'absolute', }; + this.revId++; } updateData(ctx: DimensionContext) { @@ -239,34 +274,55 @@ export class ElementState implements LayerElement { }; applyDrag = (event: OnDrag) => { - const { placement, anchor } = this; + const { options } = this; + const { placement, constraint } = options; + const { vertical, horizontal } = constraint ?? {}; const deltaX = event.delta[0]; const deltaY = event.delta[1]; const style = event.target.style; - if (anchor.top) { - placement.top! += deltaY; - style.top = `${placement.top}px`; + + const isConstrainedTop = vertical === VerticalConstraint.Top || vertical === VerticalConstraint.TopBottom; + const isConstrainedBottom = vertical === VerticalConstraint.Bottom || vertical === VerticalConstraint.TopBottom; + const isConstrainedLeft = horizontal === HorizontalConstraint.Left || horizontal === HorizontalConstraint.LeftRight; + const isConstrainedRight = + horizontal === HorizontalConstraint.Right || horizontal === HorizontalConstraint.LeftRight; + + if (isConstrainedTop) { + placement!.top! += deltaY; + style.top = `${placement!.top}px`; } - if (anchor.bottom) { - placement.bottom! -= deltaY; - style.bottom = `${placement.bottom}px`; + + if (isConstrainedBottom) { + placement!.bottom! -= deltaY; + style.bottom = `${placement!.bottom}px`; } - if (anchor.left) { - placement.left! += deltaX; - style.left = `${placement.left}px`; + + if (isConstrainedLeft) { + placement!.left! += deltaX; + style.left = `${placement!.left}px`; } - if (anchor.right) { - placement.right! -= deltaX; - style.right = `${placement.right}px`; + + if (isConstrainedRight) { + placement!.right! -= deltaX; + style.right = `${placement!.right}px`; } + + // TODO: Center + Scale }; // kinda like: // https://github.com/grafana/grafana-edge-app/blob/main/src/panels/draw/WrapItem.tsx#L44 applyResize = (event: OnResize) => { - const { placement, anchor } = this; + const { options } = this; + const { placement, constraint } = options; + const { vertical, horizontal } = constraint ?? {}; + + const top = vertical === VerticalConstraint.Top || vertical === VerticalConstraint.TopBottom; + const bottom = vertical === VerticalConstraint.Bottom || vertical === VerticalConstraint.TopBottom; + const left = horizontal === HorizontalConstraint.Left || horizontal === HorizontalConstraint.LeftRight; + const right = horizontal === HorizontalConstraint.Right || horizontal === HorizontalConstraint.LeftRight; const style = event.target.style; const deltaX = event.delta[0]; @@ -275,69 +331,62 @@ export class ElementState implements LayerElement { const dirTB = event.direction[1]; if (dirLR === 1) { // RIGHT - if (anchor.right) { - placement.right! -= deltaX; - style.right = `${placement.right}px`; - if (!anchor.left) { - placement.width = event.width; - style.width = `${placement.width}px`; + if (right) { + placement!.right! -= deltaX; + style.right = `${placement!.right}px`; + if (!left) { + placement!.width = event.width; + style.width = `${placement!.width}px`; } } else { - placement.width! = event.width; - style.width = `${placement.width}px`; + placement!.width! = event.width; + style.width = `${placement!.width}px`; } } else if (dirLR === -1) { // LEFT - if (anchor.left) { - placement.left! -= deltaX; - placement.width! = event.width; - style.left = `${placement.left}px`; - style.width = `${placement.width}px`; + if (left) { + placement!.left! -= deltaX; + placement!.width! = event.width; + style.left = `${placement!.left}px`; + style.width = `${placement!.width}px`; } else { - placement.width! += deltaX; - style.width = `${placement.width}px`; + placement!.width! += deltaX; + style.width = `${placement!.width}px`; } } if (dirTB === -1) { // TOP - if (anchor.top) { - placement.top! -= deltaY; - placement.height = event.height; - style.top = `${placement.top}px`; - style.height = `${placement.height}px`; + if (top) { + placement!.top! -= deltaY; + placement!.height = event.height; + style.top = `${placement!.top}px`; + style.height = `${placement!.height}px`; } else { - placement.height = event.height; - style.height = `${placement.height}px`; + placement!.height = event.height; + style.height = `${placement!.height}px`; } } else if (dirTB === 1) { // BOTTOM - if (anchor.bottom) { - placement.bottom! -= deltaY; - placement.height! = event.height; - style.bottom = `${placement.bottom}px`; - style.height = `${placement.height}px`; + if (bottom) { + placement!.bottom! -= deltaY; + placement!.height! = event.height; + style.bottom = `${placement!.bottom}px`; + style.height = `${placement!.height}px`; } else { - placement.height! = event.height; - style.height = `${placement.height}px`; + placement!.height! = event.height; + style.height = `${placement!.height}px`; } } - this.width = event.width; - this.height = event.height; + // TODO: Center + Scale }; render() { const { item } = this; return (
- +
); } diff --git a/public/app/features/canvas/runtime/group.tsx b/public/app/features/canvas/runtime/group.tsx index d331d745f9c..983c0b4986e 100644 --- a/public/app/features/canvas/runtime/group.tsx +++ b/public/app/features/canvas/runtime/group.tsx @@ -8,6 +8,7 @@ import { LayerActionID } from 'app/plugins/panel/canvas/types'; import { cloneDeep } from 'lodash'; import { Scene } from './scene'; import { RootElement } from './root'; +import { HorizontalConstraint, Placement, VerticalConstraint } from '../types'; export const groupItemDummy: CanvasElementItem = { id: 'group', @@ -53,27 +54,6 @@ export class GroupState extends ElementState { return false; } - // The parent size, need to set our own size based on offsets - updateSize(width: number, height: number) { - super.updateSize(width, height); - if (!this.parent) { - this.width = width; - this.height = height; - this.sizeStyle.width = width; - this.sizeStyle.height = height; - } - - // Update children with calculated size - for (const elem of this.elements) { - elem.updateSize(this.width, this.height); - } - - // The group forced to full width (for now) - this.sizeStyle.width = width; - this.sizeStyle.height = height; - this.sizeStyle.position = 'absolute'; - } - updateData(ctx: DimensionContext) { super.updateData(ctx); for (const elem of this.elements) { @@ -113,21 +93,50 @@ export class GroupState extends ElementState { return; } const opts = cloneDeep(element.options); - if (element.anchor.top) { - opts.placement!.top! += 10; - } - if (element.anchor.left) { - opts.placement!.left! += 10; - } - if (element.anchor.bottom) { - opts.placement!.bottom! += 10; - } - if (element.anchor.right) { - opts.placement!.right! += 10; + + const { constraint, placement: oldPlacement } = element.options; + const { vertical, horizontal } = constraint ?? {}; + const placement = oldPlacement ?? ({} as Placement); + + switch (vertical) { + case VerticalConstraint.Top: + case VerticalConstraint.TopBottom: + if (placement.top == null) { + placement.top = 25; + } else { + placement.top += 10; + } + break; + case VerticalConstraint.Bottom: + if (placement.bottom == null) { + placement.bottom = 100; + } else { + placement.bottom -= 10; + } + break; } + switch (horizontal) { + case HorizontalConstraint.Left: + case HorizontalConstraint.LeftRight: + if (placement.left == null) { + placement.left = 50; + } else { + placement.left += 10; + } + break; + case HorizontalConstraint.Right: + if (placement.right == null) { + placement.right = 50; + } else { + placement.right -= 10; + } + break; + } + + opts.placement = placement; + const copy = new ElementState(element.item, opts, this); - copy.updateSize(element.width, element.height); copy.updateData(this.scene.context); if (updateName) { copy.options.name = this.scene.getNextElementName(); diff --git a/public/app/features/canvas/runtime/root.tsx b/public/app/features/canvas/runtime/root.tsx index 1106adddd93..e5ba2f92a3b 100644 --- a/public/app/features/canvas/runtime/root.tsx +++ b/public/app/features/canvas/runtime/root.tsx @@ -5,21 +5,17 @@ import { Scene } from './scene'; export class RootElement extends GroupState { constructor(public options: CanvasGroupOptions, public scene: Scene, private changeCallback: () => void) { super(options, scene); + + this.sizeStyle = { + height: '100%', + width: '100%', + }; } isRoot(): this is RootElement { return true; } - // The parent size is always fullsize - updateSize(width: number, height: number) { - super.updateSize(width, height); - this.width = width; - this.height = height; - this.sizeStyle.width = width; - this.sizeStyle.height = height; - } - // root type can not change onChange(options: CanvasElementOptions) { this.revId++; @@ -28,10 +24,10 @@ export class RootElement extends GroupState { } getSaveModel(): CanvasGroupOptions { - const { placement, anchor, ...rest } = this.options; + const { placement, constraint, ...rest } = this.options; return { - ...rest, // everything except placement & anchor + ...rest, // everything except placement & constraint elements: this.elements.map((v) => v.getSaveModel()), }; } diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index da2ad559db8..809032eaf61 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -8,7 +8,7 @@ import Selecto from 'selecto'; import { config } from 'app/core/config'; import { GrafanaTheme2, PanelData } from '@grafana/data'; import { stylesFactory } from '@grafana/ui'; -import { Anchor, CanvasGroupOptions, DEFAULT_CANVAS_ELEMENT_CONFIG, Placement } from 'app/features/canvas'; +import { CanvasGroupOptions, DEFAULT_CANVAS_ELEMENT_CONFIG } from 'app/features/canvas'; import { ColorDimensionConfig, ResourceDimensionConfig, @@ -112,7 +112,6 @@ export class Scene { this.width = width; this.height = height; this.style = { width, height }; - this.root.updateSize(width, height); if (this.selecto?.getSelectedTargets().length) { this.clearCurrentSelection(); @@ -157,44 +156,16 @@ export class Scene { this.save(); } - toggleAnchor(element: ElementState, k: keyof Anchor) { - const { div } = element; - if (!div) { - console.log('Not ready'); - return; - } - - const w = element.parent?.width ?? 100; - const h = element.parent?.height ?? 100; - - // Get computed position.... - const info = div.getBoundingClientRect(); // getElementInfo(div, element.parent?.div); - console.log('DIV info', div); - - const placement: Placement = { - top: info.top, - left: info.left, - width: info.width, - height: info.height, - bottom: h - info.bottom, - right: w - info.right, - }; - - console.log('PPP', placement); - - // // TODO: needs to recalculate placement based on absolute values... - // element.anchor[k] = !Boolean(element.anchor[k]); - // element.placement = placement; - // element.validatePlacement(); - // element.revId++; - // this.revId++; - // this.save(); - - this.moved.next(Date.now()); - } - - save = () => { + save = (updateMoveable = false) => { this.onSave(this.root.getSaveModel()); + + if (updateMoveable) { + setTimeout(() => { + if (this.div) { + this.initMoveable(true); + } + }, 100); + } }; private findElementByTarget = (target: HTMLElement | SVGElement): ElementState | undefined => { @@ -262,8 +233,8 @@ export class Scene { initMoveable = (destroySelecto = false, allowChanges = true) => { const targetElements = this.generateTargetElements(this.root.elements); - if (destroySelecto) { - this.selecto?.destroy(); + if (destroySelecto && this.selecto) { + this.selecto.destroy(); } this.selecto = new Selecto({ @@ -295,9 +266,8 @@ export class Scene { .on('dragEnd', (event) => { const targetedElement = this.findElementByTarget(event.target); - if (targetedElement && targetedElement.parent) { - const parent = targetedElement.parent; - targetedElement.updateSize(parent.width, parent.height); + if (targetedElement) { + targetedElement?.setPlacementFromConstraint(); } }) .on('resize', (event) => { @@ -311,6 +281,13 @@ export class Scene { targetedElement!.applyResize(event); }); this.moved.next(Date.now()); // TODO only on end + }) + .on('resizeEnd', (event) => { + const targetedElement = this.findElementByTarget(event.target); + + if (targetedElement) { + targetedElement?.setPlacementFromConstraint(); + } }); let targets: Array = []; diff --git a/public/app/features/canvas/types.ts b/public/app/features/canvas/types.ts index 872e149cf6b..54055e1be1f 100644 --- a/public/app/features/canvas/types.ts +++ b/public/app/features/canvas/types.ts @@ -10,11 +10,25 @@ export interface Placement { height?: number; } -export interface Anchor { - top?: boolean; - left?: boolean; - right?: boolean; - bottom?: boolean; +export interface Constraint { + horizontal?: HorizontalConstraint; + vertical?: VerticalConstraint; +} + +export enum HorizontalConstraint { + Left = 'left', + Right = 'right', + LeftRight = 'leftright', + Center = 'center', + Scale = 'scale', +} + +export enum VerticalConstraint { + Top = 'top', + Bottom = 'bottom', + TopBottom = 'topbottom', + Center = 'center', + Scale = 'scale', } export enum BackgroundImageSize { diff --git a/public/app/plugins/panel/canvas/editor/LayerElementListEditor.tsx b/public/app/plugins/panel/canvas/editor/LayerElementListEditor.tsx index 492504ddf17..f637c153752 100644 --- a/public/app/plugins/panel/canvas/editor/LayerElementListEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/LayerElementListEditor.tsx @@ -38,7 +38,6 @@ export class LayerElementListEditor extends PureComponent { const newElementOptions = item.getNewOptions() as CanvasElementOptions; newElementOptions.type = item.id; const newElement = new ElementState(item, newElementOptions, layer); - newElement.updateSize(newElement.width, newElement.height); newElement.updateData(layer.scene.context); layer.elements.push(newElement); layer.scene.save(); diff --git a/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx b/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx index 6e0c4c7e9c3..c79f5e91bde 100644 --- a/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/PlacementEditor.tsx @@ -1,18 +1,32 @@ import React, { FC } from 'react'; -import { Button, Field, HorizontalGroup, InlineField, InlineFieldRow } from '@grafana/ui'; -import { StandardEditorProps } from '@grafana/data'; - -import { PanelOptions } from '../models.gen'; import { useObservable } from 'react-use'; import { Subject } from 'rxjs'; +import { Field, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui'; +import { SelectableValue, StandardEditorProps } from '@grafana/data'; + +import { PanelOptions } from '../models.gen'; import { CanvasEditorOptions } from './elementEditor'; -import { Anchor, Placement } from 'app/features/canvas'; +import { HorizontalConstraint, Placement, VerticalConstraint } from 'app/features/canvas'; import { NumberInput } from 'app/features/dimensions/editors/NumberInput'; -const anchors: Array = ['top', 'left', 'bottom', 'right']; const places: Array = ['top', 'left', 'bottom', 'right', 'width', 'height']; -export const PlacementEditor: FC> = ({ item }) => { +const horizontalOptions: Array> = [ + { label: 'Left', value: HorizontalConstraint.Left }, + { label: 'Right', value: HorizontalConstraint.Right }, + { label: 'Left and right', value: HorizontalConstraint.LeftRight }, +]; + +const verticalOptions: Array> = [ + { label: 'Top', value: VerticalConstraint.Top }, + { label: 'Bottom', value: VerticalConstraint.Bottom }, + { label: 'Top and bottom', value: VerticalConstraint.TopBottom }, +]; + +export const PlacementEditor: FC> = ({ + item, + onChange, +}) => { const settings = item.settings; // Will force a rerender whenever the subject changes @@ -26,28 +40,39 @@ export const PlacementEditor: FC???; } - const { placement } = element; + const { options } = element; + const { placement, constraint: layout } = options; + + const onHorizontalConstraintChange = (h: SelectableValue) => { + element.options.constraint!.horizontal = h.value; + element.setPlacementFromConstraint(); + settings.scene.revId++; + settings.scene.save(true); + }; + + const onVerticalConstraintChange = (v: SelectableValue) => { + element.options.constraint!.vertical = v.value; + element.setPlacementFromConstraint(); + settings.scene.revId++; + settings.scene.save(true); + }; return (
- - {anchors.map((a) => ( - - ))} - + + +
<> {places.map((p) => { - const v = placement[p]; + const v = placement![p]; if (v == null) { return null; } diff --git a/public/app/plugins/panel/canvas/editor/elementEditor.tsx b/public/app/plugins/panel/canvas/editor/elementEditor.tsx index 6a5ce60757a..649900a08cc 100644 --- a/public/app/plugins/panel/canvas/editor/elementEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/elementEditor.tsx @@ -84,7 +84,7 @@ export function getElementEditor(opts: CanvasEditorOptions): NestedPanelOptions< category: ['Layout'], id: 'content', path: '__', // not used - name: 'Anchor', + name: 'Constraints', editor: PlacementEditor, settings: opts, }); diff --git a/public/app/plugins/panel/canvas/editor/layerEditor.tsx b/public/app/plugins/panel/canvas/editor/layerEditor.tsx index ded0763413d..917b3e60573 100644 --- a/public/app/plugins/panel/canvas/editor/layerEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/layerEditor.tsx @@ -81,7 +81,7 @@ export function getLayerEditor(opts: InstanceState): NestedPanelOptions {} @@ -36,17 +37,16 @@ export class IconPanel extends Component { updateSize = (props: Props) => { const { width, height } = props; - this.element.anchor = { - top: true, - left: true, + this.element.options.constraint = { + vertical: VerticalConstraint.Top, + horizontal: HorizontalConstraint.Left, }; - this.element.placement = { + this.element.options.placement = { left: 0, top: 0, width, height, }; - this.element.updateSize(width, height); }; dims: DimensionContext = {