<!DOCTYPE HTML>
<html style="height: 100%;">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Demo</title>
    <style>
      .demoMyColorBox {
        will-change: left, top;
        background-color: #062E4F;
        border: 2px solid;
        margin: 0.75rem;
        border-radius: 25%;
        position: relative;
      }
    </style>
    <script id="sap-ui-bootstrap"
      src="https://sdk.openui5.org/nightly/resources/sap-ui-core.js"
      data-sap-ui-oninit="onUI5Init"
      data-sap-ui-libs="sap.ui.core,sap.m"
      data-sap-ui-async="true"
      data-sap-ui-theme="sap_horizon_dark"
      data-sap-ui-compatversion="edge"
      data-sap-ui-excludejquerycompat="true"
      data-sap-ui-resourceroots='{ "demo": "./" }'
      data-sap-ui-xx-waitfortheme="init"
      data-sap-ui-modules="demo/custom/control/MyColorBox,demo/custom/control/MyColorBoxRenderer"
    ></script>
    <script>
      globalThis.onUI5Init = () => sap.ui.require([
        "sap/ui/core/mvc/XMLView",
        "sap/ui/model/json/JSONModel",
      ], (XMLView, JSONModel) => {
        "use strict";
        
        const limit = 5000;
        const model = new JSONModel({});
        model.setDefaultBindingMode("OneWay");
        model.setSizeLimit(limit);
        const callback = (x, y) => {
          model.setProperty("/x", x, null, true);
          model.setProperty("/y", y, null, true);
        };

        let radius = 20;
        let x = 0;
        let y = -radius;

        XMLView.create({
          definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc" height="100%" xmlns="sap.m">
            <App autoFocus="false">
              <Page enableScrolling="false"
                class="sapUiContentPadding"
                content="{
                  path: 'limit>/items',
                  templateShareable: false
                }"
              >
                <customHeader>
                  <Bar>
                    <contentLeft>
                      <Title class="sapUiHideOnPhone"
                        text="🔩 UI5 Stress Test 🏋️"
                        titleStyle="H2"
                      />
                    </contentLeft>
                    <contentMiddle>
                      <HBox renderType="Bare"
                        alignItems="Center"
                        justifyContent="SpaceBetween"
                        height="100%"
                        width="7rem"
                        xmlns:html="http://www.w3.org/1999/xhtml"
                      >
                        <HBox renderType="Bare"
                          height="100%"
                          width="2.5rem"
                          justifyContent="SpaceBetween"
                          alignItems="Center"
                        >
                          <html:span>x:</html:span>
                          <Text text="{/x}" textAlign="End"/>
                        </HBox>
                        <HBox renderType="Bare"
                          width="2.5rem"
                          justifyContent="SpaceBetween"
                          height="100%"
                          alignItems="Center"
                        >
                          <html:span>y:</html:span>
                          <Text text="{/y}" textAlign="End"/>
                        </HBox>
                      </HBox>
                    </contentMiddle>
                    <contentRight>
                      <StepInput
                        textAlign="Center"
                        min="1"
                        max="1000"
                        fieldWidth="80%"
                        description="items"
                        width="13rem"
                        value="{limit>/size}"
                      />
                    </contentRight>
                  </Bar>
                </customHeader>
                <subHeader>
                  <Toolbar design="Info">
                    <ToolbarSpacer/>
                    <Text
                      text="DOM rendering, data synchronization, event dispatching, ..."
                    />
                  </Toolbar>
                </subHeader>
                <myControl:MyColorBox xmlns:myControl="demo.custom.control"
                  class="demoMyColorBox"
                  x="{/x}"
                  y="{/y}"
                />
              </Page>
            </App>
          </mvc:View>`,
          afterInit: function() {
            const changeHandler = event => this.getModel("limit").setProperty("/items", [
              ...Array(event.getParameter("value"))
            ], null, true);
            this.getModel("limit").attachPropertyChange(changeHandler);
          },
          models: {
            undefined: model,
            limit: (() => {
              const limit = 5000;
              const size = 50;
              const model = new JSONModel({
                size: size,
                items: [...Array(size)],
              });
              model.setSizeLimit(limit);
              return model;
            })(),
          },
          afterRendering: myFn,
        }).then(view => view.placeAt("content"));
        
        function myFn() {
          if (!radius) {
            return;
          }
          callback(x, y); // update element positions
          let a = x, b = y;
          if (y >= 0 && x > -radius) {
            a--;
          } else {
            a++;
          }
          if (x <= 0 && y > -radius) {
            b--;
          } else {
            b++;
          }
          x = a;
          y = b;
          window.requestAnimationFrame(myFn);
        }
      });    
    </script>
  </head>
  <body id="content" class="sapUiBody sapUiSizeCompact">
  </body>
</html>
sap.ui.define([
  "sap/ui/core/Control",
  "./MyColorBoxRenderer",
], function(Control, MyColorBoxRenderer) {
  "use strict";

  return Control.extend("demo.custom.control.MyColorBox", {
    renderer: MyColorBoxRenderer,
    metadata: {
      properties: {
        "x": {
          type: "int",
          bindable: true
        },
        "y": {
          type: "int",
          bindable: true
        },
      },
    },

    // ...
  });
});
sap.ui.define([
  "sap/ui/core/Renderer",
], function(Renderer) {
  "use strict";

  const boxSize = "18";
  return Renderer.extend("demo.custom.control.MyColorBoxRenderer", {
    //============================================================
		
    apiVersion: 4, // Aka. "incremental DOM" (apiVerison v2 available since 1.67.x)
    render: (renderManager, control) => renderManager
      .openStart("canvas", control)
        .style("left", `${control.getX()}px`)
        .style("top", `${control.getY()}px`)
        .attr("width", boxSize)
        .attr("height", boxSize)
      .openEnd().close("canvas"),
    
    //============================================================

    render_: (renderManager, control) => renderManager // string-based
      .write("<canvas").writeControlData(control)
        .addStyle("left", `${control.getX()}px`)
        .addStyle("top", `${control.getY()}px`)
        .writeAttribute("width", boxSize)
        .writeAttribute("height", boxSize)
			  .writeStyles()
			  .writeClasses()
			.write("></canvas>")
  });
});