var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
import { X as Promise$1, Z as lru, l as lodash, $ as tinycolor } from "./index.js";
import { l as loader, e as editorDefaults, P as utils } from "./watermark.js";
import { T as ThreeTextRenderer, g as getModelSize } from "./three-text-renderer.js";
import { s as serialize } from "./index21.js";
import { E as ElementModel } from "./background.js";
import { i as inherit, B as BaseElement } from "./base-element.js";
import "vue";
import "./v4.js";
import "./index18.js";
import "./dom.js";
import "./clone.js";
import "./flattenDeep.js";
import "./defaults.js";
import "./index15.js";
import "./gif-utils.js";
import "./gif-apng.worker.js";
import "./upng.js";
import "./api-service.js";
const createTimeoutPromise = (time) => {
  return new Promise$1((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("timeout"));
    }, time);
  });
};
function createPromiseQueue(options = {}) {
  const store = /* @__PURE__ */ new Map();
  const queue = [];
  let isRunning = false;
  const exec = async () => {
    isRunning = true;
    const id = queue.shift();
    const idQueue = store.get(id);
    const { createPromise, resolve, reject } = idQueue.pop();
    const withTimeout = [createPromise()].concat(options.timeout ? [createTimeoutPromise(options.timeout)] : []);
    try {
      const result = await Promise$1.race(withTimeout);
      resolve(result);
    } catch (err) {
      reject(err);
    }
    if (queue.length) {
      await exec();
    }
    isRunning = false;
  };
  const promiseQueue2 = {
    debounceTimer: null,
    async debounce(id, createPromise, delay = 80) {
      const promise = new Promise$1((resolve) => {
        if (this.debounceTimer) {
          clearTimeout(this.debounceTimer);
        }
        this.debounceTimer = setTimeout(() => {
          resolve();
        }, delay);
      }).then(() => {
        return this.run(id, createPromise);
      });
      return promise;
    },
    async run(id, createPromise) {
      if (!store.get(id)) {
        store.set(id, []);
      }
      if (!queue.includes(id)) {
        queue.push(id);
      }
      const promise = new Promise$1((resolve, reject) => {
        store.get(id).push({
          createPromise,
          resolve,
          reject
        });
      });
      if (!isRunning) {
        if (options.wait) {
          isRunning = true;
          await Promise$1.delay(options.wait);
        }
        exec();
      }
      return promise;
    },
    clear() {
      queue.splice(0, queue.length);
      store.clear();
      isRunning = null;
    }
  };
  return promiseQueue2;
}
function getThreeTextKey(model, zoom = 1) {
  const relativeLetterSpacing = Math.floor(model.letterSpacing / model.fontSize * 1e3) / 1e3;
  model.$relativeLetterSpacing = relativeLetterSpacing;
  let key = JSON.stringify(model.layers) + JSON.stringify(model.pointLights) + JSON.stringify(model.contents) + JSON.stringify(model.hemiLight) + JSON.stringify(model.environment) + JSON.stringify(model.shadow) + JSON.stringify(model.deformation) + JSON.stringify(model.warpByWord);
  key += model.fontSize + zoom + model.content + model.lineHeight + relativeLetterSpacing + model.textAlign + model.writingMode + model.fontFamily + model.rotate3d + model.viewAngle + model.isOrtho + model.$showCoordinate + model.isFloodLightOff;
  return key;
}
const timeOut = 2e4;
const promiseQueue = createPromiseQueue({
  timeout: timeOut
});
class ThreeTextEngine {
  constructor() {
    this.canvas = document.createElement("canvas");
    this.renderer = new ThreeTextRenderer(this.canvas);
    this.controlData = {
      hasEyeDistanceChanged: true,
      hasFontChanged: true,
      hasModelChanged: true,
      hasLightChanged: true,
      hasCameraChanged: true,
      hasMaterialsChanged: true,
      hasEnvChanged: true,
      hasCanvasResize: true,
      hasShadowChanged: true,
      hasCoordChanged: true
    };
    this.materialsSignals = [true, true, true, true, true, true];
    this.canvasMap = new lru.LRUMap(10);
    this.init();
  }
  async init() {
    if (!this.initialized) {
      await this.renderer.init();
      this.initialized = true;
    }
  }
  async prepareFont(model) {
    loader.loadFont(__spreadValues({}, model.$fontData), timeOut);
    await this.renderer.prepareFont(model);
  }
  async renderAll(outControlData, model, outCanvas) {
    if (!model.$fontData) {
      this.renderer.meshError = true;
      return;
    }
    if (outControlData.mode !== "preview" && outControlData.compositeZoom !== this.canvas.compositeZoom) {
      outControlData.hasCanvasResize = true;
    }
    if (!this.initialized) {
      await this.init();
    }
    const { controlData, renderer, canvas } = this;
    Object.assign(controlData, outControlData);
    this.initControlData(outControlData, false);
    this.compareModel(controlData, this.model, model);
    const key = getThreeTextKey(model, outControlData.compositeZoom);
    const stashCanvas = this.canvasMap.get(key);
    let resultCanvas;
    if (stashCanvas) {
      resultCanvas = stashCanvas;
    } else {
      this.model = lodash.exports.cloneDeep(model);
      if (!controlData.hasModelChanged && controlData.hasEyeDistanceChanged) {
        renderer.updateBBox(model);
        renderer.updateEyeDistance(model);
      }
      if (controlData.hasFontChanged) {
        await this.prepareFont(model);
      }
      if (controlData.hasMaterialsChanged) {
        await renderer.loadMaterials(model, this.materialsSignals);
        const layer = model.layers[0];
        const sideMaterials = layer.sideMaterials.enable ? layer.sideMaterials : layer.frontMaterials;
        const bevelMaterials = layer.bevelMaterials.enable ? layer.bevelMaterials : sideMaterials;
        const materials = [layer.frontMaterials, bevelMaterials, sideMaterials];
        renderer.updateMaterials(materials, this.materialsSignals);
      }
      if (controlData.hasEnvChanged) {
        await renderer.updateEnvironment(model);
      }
      if (!controlData.hasModelChanged && (controlData.hasCanvasResize || controlData.hasEyeDistanceChanged)) {
        renderer.updateCanvasSize(model, outControlData.compositeZoom);
      }
      if (controlData.hasLightChanged) {
        renderer.updateFloodLights(model);
      }
      if (controlData.hasModelChanged || controlData.hasFontChanged) {
        try {
          await renderer.updateTextModel(model);
          renderer.updateCanvasSize(model, controlData.compositeZoom);
          renderer.updateCamera(model);
          renderer.meshError = false;
        } catch (error) {
          renderer.meshError = true;
          throw error;
        }
      }
      if (!controlData.hasModelChanged && (controlData.hasCameraChanged || controlData.hasEyeDistanceChanged)) {
        renderer.updateCamera(model);
      }
      if (controlData.hasShadowChanged) {
        renderer.updateShadow(model);
      }
      if (Object.keys(controlData).some((key2) => {
        const istrue = controlData[key2] === true;
        return istrue;
      })) {
        renderer.render(model);
        if (!renderer.meshError) {
          const mvpMatrix = renderer.commonUniforms.state.u_MVPMatrix;
          const shadowMatrix = renderer.shadowUniforms.state.u_ShadowMatrix;
          if (!renderer.boundingBox) {
            renderer.boundingBox = renderer.updateBBox(model);
          }
          canvas.modelCube = getModelSize(renderer.boundingBox, mvpMatrix, shadowMatrix, model.shadow);
        }
      }
      if (controlData.hasModelChanged) {
        const cacheCanvas = document.createElement("canvas");
        cacheCanvas.width = this.canvas.width;
        cacheCanvas.height = this.canvas.height;
        const ctx = cacheCanvas.getContext("2d");
        if (!renderer.meshError) {
          ctx.drawImage(this.canvas, 0, 0);
          cacheCanvas.modelCube = lodash.exports.cloneDeep(canvas.modelCube);
          cacheCanvas.compositeZoom = canvas.compositeZoom;
          cacheCanvas.scaleRatio = canvas.scaleRatio;
          this.canvasMap.set(key, cacheCanvas);
        }
        resultCanvas = cacheCanvas;
      } else {
        resultCanvas = canvas;
      }
    }
    if (!(resultCanvas && resultCanvas.width)) {
      return;
    }
    const outCtx = outCanvas.getContext("2d");
    outCtx.clearRect(0, 0, outCanvas.width, outCanvas.height);
    if (!renderer.meshError) {
      outCanvas.width = resultCanvas.width;
      outCanvas.height = resultCanvas.height;
      outCanvas.modelCube = lodash.exports.cloneDeep(resultCanvas.modelCube);
      outCanvas.compositeZoom = resultCanvas.compositeZoom;
      outCanvas.scaleRatio = resultCanvas.scaleRatio;
      outCtx.drawImage(resultCanvas, 0, 0);
    }
  }
  async requestRenderAll(controlData, model, canvas) {
    if (!controlData || !model || !canvas) {
      throw new Error("requestRenderAll \u83B7\u53D6\u6570\u636E\u5F02\u5E38");
    }
    const promise = await promiseQueue.run(canvas, this.renderAll.bind(this, controlData, model, canvas));
    return promise;
  }
  initControlData(controlData, state = false) {
    for (const data in controlData) {
      if (/^has/.test(data)) {
        controlData[data] = state;
      }
    }
  }
  compareModel(controlData, model1, model2) {
    if (!model1 || !model2) {
      this.initControlData(controlData, true);
      return;
    }
    controlData.hasEyeDistanceChanged = model1.viewAngle !== model2.viewAngle || model1.isOrtho !== model2.isOrtho;
    controlData.hasFontChanged = controlData.hasFontChanged || model1.fontFamily !== model2.fontFamily;
    controlData.hasModelChanged = this.getWetherModelChanged(model1, model2);
    controlData.hasLightChanged = controlData.hasLightChanged || !lodash.exports.isEqual(model1.pointLights, model2.pointLights) || !lodash.exports.isEqual(model1.hemiLight, model2.hemiLight) || model1.isFloodLightOff !== model2.isFloodLightOff;
    controlData.hasCameraChanged = !lodash.exports.isEqual(model1.rotate3d, model2.rotate3d) || model1.isOrtho !== model2.isOrtho;
    controlData.hasMaterialsChanged = this.getWetherMaterialChanged(model1, model2);
    controlData.hasEnvChanged = controlData.hasEnvChanged || !lodash.exports.isEqual(model1.environment, model2.environment);
    controlData.hasCanvasResize = controlData.hasCanvasResize || model1.fontSize !== model2.fontSize;
    controlData.hasShadowChanged = !lodash.exports.isEqual(model1.shadow, model2.shadow);
    controlData.hasCoordChanged = model1.$showCoordinate !== model2.$showCoordinate;
  }
  getWetherModelChanged(model1, model2) {
    const layer1 = model1.layers[0];
    const layer2 = model2.layers[0];
    const isChanged = this.hasContentsChanged(model1.contents, model2.contents) || model1.fontFamily !== model2.fontFamily || !lodash.exports.isEqual(model1.deformation, model2.deformation) || !lodash.exports.isEqual(model1.warpByWord, model2.warpByWord) || model1.textAlign !== model2.textAlign || model1.letterSpacing !== model2.letterSpacing || model1.lineHeight !== model2.lineHeight || model1.shadow.enable !== model2.shadow.enable || layer1.bevelSize !== layer2.bevelSize || layer1.bevelThickness !== layer2.bevelThickness || layer1.bevelSegments !== layer2.bevelSegments || layer1.curveSegments !== layer2.curveSegments || layer1.extrudeDepth !== layer2.extrudeDepth || layer1.extrudeOffsetX !== layer2.extrudeOffsetX || layer1.extrudeOffsetY !== layer2.extrudeOffsetY || layer1.expand !== layer2.expand;
    return isChanged;
  }
  getWetherMaterialChanged(model1, model2) {
    const layer1 = model1.layers[0];
    const layer2 = model2.layers[0];
    const getMaterialTexChange = (material1, material2) => {
      return material1.enable !== material2.enable || material1.metalRoughness !== material2.metalRoughness || material1.normal !== material2.normal || material1.albedo.image !== material2.albedo.image;
    };
    this.materialsSignals[0] = getMaterialTexChange(layer1.frontMaterials, layer2.frontMaterials);
    this.materialsSignals[1] = this.materialsSignals[0] || !lodash.exports.isEqual(layer1.frontMaterials, layer2.frontMaterials);
    this.materialsSignals[4] = layer2.sideMaterials.enable ? getMaterialTexChange(layer1.sideMaterials, layer2.sideMaterials) : this.materialsSignals[0];
    this.materialsSignals[5] = layer1.sideMaterials.enable || layer2.sideMaterials.enable ? this.materialsSignals[4] || !lodash.exports.isEqual(layer1.sideMaterials, layer2.sideMaterials) : this.materialsSignals[1];
    this.materialsSignals[2] = layer2.bevelMaterials.enable ? getMaterialTexChange(layer1.bevelMaterials, layer2.bevelMaterials) : this.materialsSignals[4];
    this.materialsSignals[3] = layer1.bevelMaterials.enable || layer2.bevelMaterials.enable ? this.materialsSignals[2] || !lodash.exports.isEqual(layer1.bevelMaterials, layer2.bevelMaterials) : this.materialsSignals[5];
    return this.materialsSignals.some((signal) => signal);
  }
  hasContentsChanged(oldContents, newContents) {
    const i = oldContents.length;
    const j = newContents.length;
    if (i !== j) {
      return true;
    }
    for (let k = 0; k < i; k++) {
      const isChanged = oldContents[k].content !== newContents[k].content;
      if (isChanged) {
        return true;
      }
    }
    return false;
  }
}
var methods = {
  changeThreeTextContents(props, element, makeSnapshot) {
    element = this.getElement(element);
    const richText = this.currentRichText;
    if (element.type !== "threeText")
      return;
    if (!element.$editing) {
      element.contents = serialize.injectStyleProps(element.contents, props);
      lodash.exports.merge(element, props);
      makeSnapshot && this.makeSnapshot("change_text_contents");
    } else if (richText) {
      Object.keys(props).forEach((name) => richText.cmd.do(name, props[name]));
    }
  },
  convertThreeTextToText(element, layout = this.currentLayout) {
    element = this.getElement(element);
    if (!element) {
      return;
    }
    const defaultElement = editorDefaults.element;
    const defaultTextElement = editorDefaults.textElement;
    const props = [].concat(Object.keys(defaultTextElement)).concat(Object.keys(defaultElement));
    const data = lodash.exports.pick(element, props);
    data.type = "text";
    data.resize = 5;
    data.version = editorDefaults.version;
    const getColor = (albedo) => [albedo.color, "#000000", albedo.gradient.stops[0].color][albedo.type];
    data.color = getColor(element.layers[0].frontMaterials.albedo);
    this.calculateBox(data);
    const centerX = element.left - element.centerRatioX * element.width;
    const centerY = element.top - element.centerRatioY * element.height;
    data.left = centerX - 0.5 * data.width;
    data.top = centerY - 0.5 * data.height;
    const newElement = this.replaceElement(element, data, layout);
    this.focusElement(newElement);
    return newElement;
  },
  async safeThreeTextRender(controlData, model, canvas) {
    if (!this.$threeTextRenderer) {
      this.$threeTextRenderer = new ThreeTextEngine();
    }
    try {
      await this.$threeTextRenderer.requestRenderAll(controlData, model, canvas);
    } catch (e) {
      console.info(e);
    }
  },
  async getThreeTextCanvas(element) {
    const sourceCanvas = document.createElement("canvas");
    const controlData = {
      compositeZoom: 2,
      hasCanvasResize: true
    };
    await this.safeThreeTextRender(controlData, element, sourceCanvas);
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const { width, height, modelCube = [-1, 1, -1, 1] } = sourceCanvas;
    canvas.width = element.width;
    canvas.height = element.height;
    const sx = Math.floor((modelCube[0] + 1) / 2 * width);
    const sy = Math.floor((1 - modelCube[3]) / 2 * height);
    const sWidth = width >= 4096 ? Math.floor((modelCube[1] - modelCube[0]) / 2 * width) : canvas.width * controlData.compositeZoom;
    const sHeight = width >= 4096 ? Math.floor((modelCube[3] - modelCube[2]) / 2 * height) : canvas.height * controlData.compositeZoom;
    ctx.drawImage(sourceCanvas, sx, sy, sWidth, sHeight, 0, 0, canvas.width, canvas.height);
    return canvas;
  }
};
var defaultModel = {
  type: "threeText",
  width: 419.6304975086487,
  height: 467.4851256880163,
  left: 210.84898372717376,
  top: -15.806265302265814,
  transform: {
    a: 1,
    b: 0,
    c: 0,
    d: 1,
    tx: 0,
    ty: 0
  },
  resize: 1,
  filter: {
    hueRotate: 0,
    saturate: 0,
    brightness: 0,
    gaussianBlur: 0
  },
  rotate3d: [0.4400000000000002, -0.5800000000000001, 0],
  fontFamily: "Reeji - CloudYuanCu - GB - Regular",
  layers: [
    {
      frontMaterials: {
        metalRoughness: "#00ffff",
        normal: "#807fff",
        albedo: {
          type: 1,
          image: "https://st0.dancf.com/csc/147/material-three-textures/0/20190606-150053-46e8.jpg",
          color: "#ace030ff",
          gradient: {
            angle: 0,
            stops: [
              {
                color: "#ffffffff",
                offset: 0
              },
              {
                color: "#000000ff",
                offset: 1
              }
            ],
            direction: [1, 0, 0],
            type: 0,
            face: 0
          },
          texRotateAngle: 0,
          texTranslate: [0, 0]
        },
        metalStrength: 0.4252873563218391,
        roughnessStrength: 0.25287356321839083,
        albedoStrength: 1,
        normalStrength: 0,
        normalDisable: false,
        scale: 1
      },
      sideMaterials: {
        enable: false,
        metalRoughness: "#00ffff",
        normal: "#807fff",
        albedo: {
          type: 0,
          image: "",
          color: "#0008ffff",
          gradient: {
            angle: 0,
            stops: [
              {
                color: "#ffffffff",
                offset: 0
              },
              {
                color: "#000000ff",
                offset: 1
              }
            ],
            direction: [1, 0, 0],
            type: 0,
            face: 0
          },
          texRotateAngle: 0,
          texTranslate: [0, 0]
        },
        metalStrength: 1,
        roughnessStrength: 1,
        albedoStrength: 1,
        normalStrength: 0,
        normalDisable: false,
        scale: 1
      },
      bevelMaterials: {
        enable: false,
        metalRoughness: "#00ffff",
        normal: "#807fff",
        albedo: {
          type: 0,
          image: "",
          color: "#ff00ffff",
          gradient: {
            angle: 0,
            stops: [
              {
                color: "#ffffffff",
                offset: 0
              },
              {
                color: "#000000ff",
                offset: 1
              }
            ],
            direction: [1, 0, 0],
            type: 0,
            face: 0
          },
          texRotateAngle: 0,
          texTranslate: [0, 0]
        },
        metalStrength: 1,
        roughnessStrength: 0,
        albedoStrength: 1,
        normalStrength: 2,
        normalDisable: false,
        scale: 1
      },
      bevelSize: 80,
      bevelThickness: 10,
      bevelSegments: 4,
      bevelType: "quadEllipse",
      curveSegments: 1,
      extrudeDepth: 40,
      extrudeOffsetX: 0,
      extrudeOffsetY: 0,
      extrudeScale: 0,
      shadingSmoothAngle: 50,
      extrudeScaleX: 0,
      extrudeScaleY: 0,
      expand: 0
    }
  ],
  pointLights: [],
  viewAngle: 30,
  environment: {
    enable: true,
    maps: ["https://st-gdx.dancf.com/gaodingx/17/design/three/20190530-210836-623d.jpg"],
    strength: 1.031914893617021,
    rotate3d: [0, 0, 0]
  },
  fontSize: 200,
  content: "a",
  lineHeight: 1,
  letterSpacing: 0,
  textAlign: "center",
  writingMode: "horizontal-tb",
  isOrtho: false,
  shadow: {
    enable: false,
    type: "projection-2d",
    blur: 10,
    color: "#000000ff",
    offset: 0,
    opacity: 1,
    angle: 0,
    isBindRotate: false,
    offsetRatio: 1
  },
  deformation: {
    type: "none",
    intensity: 0,
    intensity1: 0,
    extrudeScaleX: 0,
    extrudeScaleY: 0
  },
  warpByWord: {
    enable: false,
    intensity: 0,
    intensity1: 0,
    randNum: 1e3,
    pattern: "1",
    offsetX: 0
  },
  modelCube: [-0.7524567801774561, 0.7734723016721756, -0.9387875937860526, 0.7611583178067339],
  centerRatioX: -0.49311386035409793,
  centerRatioY: -0.44775443301814033,
  imageUrl: "",
  $showCoordinate: false,
  isMesh: false,
  hemiLight: {
    enable: false,
    color: "#ffffff",
    dir: [0, 0, 1],
    strength: 1
  },
  isFloodLightOff: false
};
class ThreeTextModel extends ElementModel {
  constructor(data) {
    super(data);
    if (!this.contents || !this.contents.length) {
      this.contents = serialize.fromJSON(this.content || "", this);
    }
    lodash.exports.defaultsDeep(this, defaultModel);
    const { frontMaterials, sideMaterials, bevelMaterials } = this.layers[0];
    const isWhite = (color2) => color2.toHex8String().toLowerCase() === "#ffffffff";
    let color = tinycolor("#000");
    const materials = [frontMaterials, sideMaterials, bevelMaterials];
    for (let i = 0; i < materials.length; i++) {
      const baseColor = tinycolor(materials[i].albedo.color);
      if (!isWhite(baseColor)) {
        color = baseColor;
        break;
      }
    }
    const layer = this.layers[0];
    layer.expand = layer.expand || layer.scale || 0;
    delete layer.scale;
    this.contents = this.contents.map((content) => {
      return Object.assign(content, {
        color: color.toHex8String(),
        fontFamily: this.fontFamily,
        fontStyle: this.fontStyle || "normal",
        fontSize: this.fontSize,
        fontWeight: this.fontWeight || 400,
        textDecoration: this.textDecoration || "none"
      });
    }).filter((item) => item.content);
    if (layer.extrudeScaleX || layer.extrudeScaleY) {
      this.deformation.extrudeScaleX = layer.extrudeScaleX;
      this.deformation.extrudeScaleY = layer.extrudeScaleY;
      delete layer.extrudeScaleX;
      delete layer.extrudeScaleY;
    }
  }
}
var ThreeTextModel$1 = ThreeTextModel;
var template = `<div
    class="editor-element"
    :class="[
        'editor-element-' + model.type,
        model.lock ? 'editor-element-lock' : '',
        model.hidden ? 'editor-element-hidden' : '',
        model.frozen ? 'editor-element-frozen' : '',
        model.$loaded ? '' : 'editor-element-loading',
        model.$selected ? 'editor-element-selected' : '',
        model.$editing ? 'editor-element-editing' : '',
        linkSelected ? 'editor-element-link-selected' : '',
        errorMessage ? 'editor-element-error' : ''
    ]"
    :style="baseStyle"
>
    <div class="element-main">
        <div class="three-text" :style="canvasStyle">
            <div
                class="element-main"
                v-if="need2DText"
                :style="textStyle"
                v-html="model.content"
            ></div>
            <img
                v-if="showWithImg"
                crossorigin="anonymous"
                :src="model.imageUrl"
                ref="img"
                class="three-text-img"
                :style="{
                opacity: opacity,
            }"
            />
            <canvas
                ref="glCanvas"
                width="200"
                height="200"
                v-else
                class="three-text-result"
                :style="{
                transform: 'scale('+ compositeScaleRatio +')',
                marginLeft: diviateX + 'px',
                marginTop: diviateY + 'px',
                opacity: opacity,
            }"
            ></canvas>
        </div>
    </div>

    <div class="element-tips-loading" v-if="isRendering && isNeedTime && isDesignMode">
        <i class="fa fa-spin fa-spinner"></i>
    </div>

    <ElementCommon
        :element="model"
        :options="options"
        :global="global"
        :editor="editor"
        :layout="editor.currentLayout"
        :hideBlink="hideBlink"
        :isShowBlink="isShowBlink"
        :bgNinePatch="bgNinePatch"
    />
</div>
`;
var ThreeTextElement = inherit(BaseElement, {
  name: "threeText-element",
  template,
  props: ["editor", "global", "model", "options"],
  data() {
    return {
      layerPickerSignal: false,
      renderInit: false,
      renderInitOver: false,
      scaleRatio: 1,
      compositeScaleRatio: 1,
      need2DText: false,
      isRendering: true,
      isNeedTime: false,
      controlData: {
        hasEyeDistanceChanged: true,
        hasFontChanged: true,
        hasModelChanged: true,
        hasLightChanged: true,
        hasCameraChanged: true,
        hasMaterialsChanged: true,
        hasEnvChanged: true,
        hasCanvasResize: true,
        hasShadowChanged: true,
        compositeZoom: this.global.zoom * window.devicePixelRatio
      },
      devicePixelRatio: window && window.devicePixelRatio || 1
    };
  },
  computed: {
    supportTransform() {
      return !!this.model.containerTransform;
    },
    canvasStyle() {
      return {
        overflow: this.model.$showCoordinate ? "visible" : "hidden"
      };
    },
    diviateX() {
      const offsetX = 2 * (-(this.model.centerRatioX || -0.5) - 0.5) * this.model.width;
      return offsetX * this.global.zoom;
    },
    diviateY() {
      const offsetY = 2 * (-(this.model.centerRatioY || -0.5) - 0.5) * this.model.height;
      return offsetY * this.global.zoom;
    },
    opacity() {
      return this.model.opacity;
    },
    originalContent() {
      let content = "";
      const { contents } = this.model;
      contents.forEach((data) => {
        content += data.content;
      });
      return content;
    },
    isPreviewMode() {
      return this.options.mode === "preview";
    },
    isMirrorMode() {
      return this.options.mode === "mirror" && this.model.imageUrl;
    },
    showPlainText() {
      return !this.model.imageUrl && this.isRendering;
    },
    textStyle() {
      return {
        fontFamily: this.model.fontFamily,
        fontSize: this.model.fontSize + "px",
        verticalAlign: this.model.verticalAlign,
        color: this.model.layers[0].frontMaterials.albedo.color,
        transform: this.model.transform,
        transformOrigin: "0 0",
        width: this.model.width,
        height: this.model.height,
        opacity: this.showPlainText ? 1 : 0,
        lineHeight: this.model.height + "px"
      };
    },
    linkSelected() {
      const element = this.editor.currentSubElement || this.editor.currentElement || {};
      return this.isLinkWith(element);
    },
    showWithImg() {
      return !this.renderInit;
    }
  },
  methods: {
    async load() {
      this.initControlData();
      this.initModelWatcher();
      this.initLayerWatcher();
      this.syncColorToContents();
      if (this.model.imageUrl) {
        await utils.loadImage(this.model.imageUrl, this.options.fitCrossOrigin);
      } else {
        await this.multipleRender(false);
      }
    },
    async initPreviewCanvas() {
      this.renderInit = true;
      await this.$nextTick();
      this.canvas = this.$refs.glCanvas;
      this.ctx = this.canvas.getContext("2d");
      this.renderInitOver = true;
    },
    initControlData() {
      const { controlData } = this;
      controlData.hasEyeDistanceChanged = false;
      controlData.hasFontChanged = false;
      controlData.hasModelChanged = false;
      controlData.hasLightChanged = false;
      controlData.hasCameraChanged = false;
      controlData.hasMaterialsChanged = false;
      controlData.hasEnvChanged = false;
      controlData.hasCanvasResize = false;
      controlData.hasShadowChanged = false;
      controlData.compositeZoom = this.global.zoom * window.devicePixelRatio;
      controlData.mode = this.options.mode;
    },
    initModelWatcher() {
      [
        "model.shadow",
        "model.deformation",
        "model.warpByWord",
        "model.environment",
        "model.pointLights",
        "model.hemiLight"
      ].forEach((prop) => {
        this.$watch(prop, {
          deep: true,
          handler() {
            this.multipleRender();
          }
        });
      });
      [
        "model.isOrtho",
        "model.viewAngle",
        "model.isFloodLightOff",
        "model.$showCoordinate"
      ].forEach((prop) => {
        this.$watch(prop, () => {
          this.multipleRender();
        });
      });
      [
        "model.content",
        "model.lineHeight",
        "model.letterSpacing",
        "model.textAlign",
        "model.writingMode",
        "originalContent"
      ].forEach((prop) => {
        this.$watch(prop, () => {
          this.controlData.hasModelChanged = true;
        });
      });
    },
    initLayerWatcher() {
      const { model } = this;
      const reMaterials = /Materials/;
      const keys = Object.keys(model.layers[0]);
      const materialTypes = keys.filter((key) => reMaterials.test(key));
      const modelProps = keys.filter((key) => !reMaterials.test(key));
      const handleByUpdateMaterials = (target) => this.$watch(target, () => {
        this.controlData.hasMaterialsChanged = true;
      });
      const handleByUpdateModel = (target) => this.$watch(target, () => {
        this.controlData.hasModelChanged = true;
      });
      this.model.layers.forEach((layer) => {
        materialTypes.forEach((materialType) => {
          const materials = layer[materialType];
          handleByUpdateMaterials(() => materials.metalRoughness);
          handleByUpdateMaterials(() => materials.normal);
          handleByUpdateMaterials(() => materials.scale);
          handleByUpdateMaterials(() => Object.assign({}, lodash.exports.cloneDeep(materials.albedo)));
          if (materials.enable !== void 0) {
            handleByUpdateMaterials(() => materials.enable);
          }
          handleByUpdateMaterials(() => materials.metalStrength);
          handleByUpdateMaterials(() => materials.roughnessStrength);
          handleByUpdateMaterials(() => materials.albedoStrength);
          handleByUpdateMaterials(() => materials.normalStrength);
          handleByUpdateMaterials(() => materials.normalDisable);
        });
        modelProps.forEach((prop) => {
          handleByUpdateModel(() => layer[prop]);
        });
      });
    },
    async initRenderer() {
      this.model.resize = 1;
      this.model.$fontData = this.getFontData();
      await this.initPreviewCanvas();
    },
    async multipleRender(needUpdateImageUrl = true) {
      if (this.editor.global.$draging)
        return;
      this.isRendering = true;
      if (needUpdateImageUrl) {
        this.model.imageUrl = null;
      }
      if (!this.renderInitOver) {
        await this.initRenderer();
      }
      try {
        setTimeout(() => {
          this.isNeedTime = true;
        }, 400);
        this.controlData.compositeZoom = this.global.zoom * window.devicePixelRatio;
        await this.editor.safeThreeTextRender(this.controlData, this.model, this.canvas);
        this.setBBox();
        this.initControlData();
        if (!this.layerPickerSignal && this.isDesignMode) {
          this.layerPickerSignal = true;
          this.editor.lazyUpdatePicker();
        }
        this.need2DText = false;
      } catch (error) {
        this.need2DText = true;
        console.error(error);
        this.$events.$emit("element.loadError", error, this.model);
      }
      this.isNeedTime = false;
      this.isRendering = false;
      this.scaleRatio = 1;
      this.compositeScaleRatio = this.scaleRatio * this.global.zoom / this.canvas.compositeZoom;
    },
    setBBox() {
      const { model, canvas } = this;
      const { modelCube, compositeZoom } = canvas;
      if (modelCube) {
        model.modelCube.forEach((val, i) => {
          model.modelCube[i] = modelCube[i];
        });
        let { top, left, width, height, rotation } = model;
        let x = (-0.5 - model.centerRatioX) * width;
        let y = (-0.5 - model.centerRatioY) * height;
        let diviateX = x * Math.cos(rotation) - y * Math.sin(rotation);
        let diviateY = x * Math.sin(rotation) + y * Math.cos(rotation);
        const [centerX, centerY] = [
          left + 0.5 * width + diviateX,
          top + 0.5 * height + diviateY
        ];
        width = (modelCube[1] - modelCube[0]) * 0.5 * canvas.width / compositeZoom;
        height = (modelCube[3] - modelCube[2]) * 0.5 * canvas.height / compositeZoom;
        model.centerRatioX = modelCube[0] / (modelCube[1] - modelCube[0]);
        model.centerRatioY = -modelCube[3] / (modelCube[3] - modelCube[2]);
        x = (0.5 + model.centerRatioX) * width;
        y = (0.5 + model.centerRatioY) * height;
        diviateX = x * Math.cos(rotation) - y * Math.sin(rotation);
        diviateY = x * Math.sin(rotation) + y * Math.cos(rotation);
        const newLeft = centerX + diviateX - 0.5 * width;
        const newTop = centerY + diviateY - 0.5 * height;
        const dw = width - model.width;
        const dh = height - model.height;
        if (!isNaN(newLeft * newTop) && Math.hypot(dw, dh) > 0.1) {
          model.left = newLeft;
          model.top = newTop;
          model.width = width;
          model.height = height;
          const groups = this.editor.getParentGroups(this.model);
          for (let i = groups.length - 1; i >= 0; i--) {
            this.$events.$emit("group.boundingReset", groups[i]);
          }
        }
      }
    },
    getFontData() {
      return this.options.fontsMap[this.model.fontFamily || this.options.defaultFont];
    },
    syncColorToContents() {
      this.$watch(() => {
        const { frontMaterials } = this.model.layers[0];
        return frontMaterials.albedo.color;
      }, (color) => {
        this.model.contents.forEach((content) => {
          content.color = color;
        });
      });
    }
  },
  events: {
    "element.transformStart"(model) {
      if (model !== this.model)
        return;
      this.oldWith = this.model.width;
      this.oldFontSize = this.model.fontSize;
      this.oldLetterSpacing = this.model.letterSpacing;
    },
    "element.transformResize"(drag, model) {
      if (model !== this.model)
        return;
      this.scaleRatio = this.model.width / this.oldWith;
      const canvasScaleRaito = this.global.zoom / (this.canvas && this.canvas.compositeZoom || 1);
      this.compositeScaleRatio = this.scaleRatio * canvasScaleRaito;
      this.model.fontSize = this.oldFontSize * this.scaleRatio;
      this.model.contents.forEach((text) => {
        this.$set(text, "fontSize", this.model.fontSize);
      });
      this.model.letterSpacing = this.oldLetterSpacing * this.scaleRatio;
    },
    "element.transformEnd"(model, drag, { action }) {
      if (this.isModelRelative(model) && action === "resize") {
        this.controlData.hasCanvasResize = true;
        this.multipleRender();
      }
    },
    "element.change"(model, propName) {
      if (propName === "contents" && this.isLinkWith(model)) {
        const content = model.contents.reduce((list, content2) => {
          list.push(content2.content);
          return list;
        }, []).join("");
        this.editor.changeElement({
          contents: [{ content }],
          content
        }, this.model, false);
        this.syncRect();
      }
    }
  },
  watch: {
    "controlData.hasModelChanged"(val) {
      if (val) {
        if (!this._lazyModelRender) {
          this._lazyModelRender = lodash.exports.throttle(async () => {
            this.scaleRatio = 1;
            await this.multipleRender();
          }, 2e3);
        }
        this._lazyModelRender();
      }
    },
    "model.fontSize"() {
      this.hasCanvasResize = true;
      this.multipleRender();
    },
    "controlData.hasMaterialsChanged"(val) {
      if (val) {
        this.multipleRender();
      }
    },
    "model.fontFamily"() {
      this.controlData.hasFontChanged = true;
      this.controlData.hasModelChanged = true;
      this.model.$fontData = this.getFontData();
    },
    "model.rotate3d"() {
      this.controlData.hasCameraChanged = true;
      this.multipleRender();
    },
    "global.zoom"(val) {
      if (this.global.$loaded || this.editor.currentLayout.$loaded) {
        this.controlData.compositeZoom = val;
        this.multipleRender(false);
      }
    }
  }
});
var index = {
  model: ThreeTextModel$1,
  methods,
  layoutComponent: ThreeTextElement
};
export { index as default };
