import { EditorProperties, EditorProperty, Infer, f, y } from '@iplusplus/y-model'; import * as createjs from 'createjs-module'; import { TypedControl, createControlFactory } from '../TypedControl'; import { ControlData, Size, Control } from '../types'; export type ContainerControlPointsTypeInfo = { title: string, editorType: string } export type ContainerControlData = ControlData & { sampleControlData: ControlData, customName?: string, pointsTypeInfo: ContainerControlPointsTypeInfo } const PropDefine = f([ ["arrangement", "排列方向", "enum:horizontal=水平;vertical=垂直", y.string("vertical")], ["autoScale", "自动缩放子项", "enable", y.number(0)], ["autoItemInterval", "自动子项间隔", "enable", y.number(0)], ["itemInterval", "手工子项间隔", "number", y.number(0)], ["overflowShow", "溢出显示", "enable", y.number(1)], ["carouselInterval", "轮播间隔", "number", y.number(0).description("单位秒,配置为0表示不轮播")], ] as const); type PositonInfo = { x: number, y: number, width: number, height: number } type ContainerControlProps = Infer function calcAutoInterval(totalSize: number, itemSize: number, itemCount: number) { return itemCount > 1 ? (totalSize - itemSize * itemCount) / (itemCount - 1) : 0 } function calcItemsPoisition(itemCount: number, itemSize: Size, containerSize: Size, p: ContainerControlProps): PositonInfo[] { const result: PositonInfo[] = [] if (itemCount === 0) return result; const xyPropName = p.arrangement === "horizontal" ? "x" : "y"; const whPropName = p.arrangement === "horizontal" ? "width" : "height"; const whPropName2 = p.arrangement === "horizontal" ? "height" : "width"; const totalSize = p.arrangement === "horizontal" ? containerSize.width : containerSize.height; const totalSize2 = p.arrangement === "horizontal" ? containerSize.height : containerSize.width; for (let i = 0; i < itemCount; i++) { result.push({ x: 0, y: 0, width: itemSize.width, height: itemSize.height }) } if (p.autoScale) { const interval = p.carouselInterval > 0 ? totalSize : totalSize / itemCount; result.forEach((p, i) => { p[xyPropName] = interval * i p[whPropName] = interval; p[whPropName2] = totalSize2; }) } else { const interval = p.autoItemInterval ? calcAutoInterval(totalSize, itemSize[whPropName], itemCount) : p.itemInterval result.forEach((p, i) => { p[xyPropName] = (itemSize[whPropName] + interval) * i }) } return result; } export class ContainerControl extends TypedControl { static readonly typeName = "Container" static readonly title = "容器控件" // sampleControl !:Control extendsProp?: EditorProperty; //subControlsProps: any[]=[] customName?: string subControls: Control[] = [] innerContainer: createjs.Container = new createjs.Container(); containerControlData !: ContainerControlData cp !: Infer & { dataPoints: any[] } subControlsPropsCache?: any[] maskShape: createjs.Shape = new createjs.Shape() carouselTimer?: number; getDefaultSize(): Size { return { width: 200, height: 100 } } assembleComponents(): void { this.containerControlData = this.controlData as ContainerControlData; this.customName = this.containerControlData.customName this.cp = this.p as any; this.cp.dataPoints = this.containerControlData.customProperties.dataPoints as any[]; // this.subControlsProps = this.containerControlData.subControlsProps if (!this.api) return; this.maskShape.visible = false; this.container.addChild(this.innerContainer); this.container.addChild(this.maskShape); const sampleControl = this.api.createControl(this.containerControlData.sampleControlData) sampleControl.initControl(this.api); const props = sampleControl.getProperties(); const sampleValues = this.containerControlData.sampleControlData.customProperties; props.forEach(p => { const anyP = p as any; let defaultValue = anyP.defaultValueOverride; if (defaultValue !== undefined) return; defaultValue = sampleValues[p.name]; if (defaultValue !== undefined && p.valueType.validate(defaultValue)) { anyP.defaultValueOverride = defaultValue; } }) sampleControl.destroy(); const pointsTypeInfo = this.containerControlData.pointsTypeInfo; if (pointsTypeInfo === undefined) { this.extendsProp = (this.containerControlData as unknown as {baseOnDevice:boolean }).baseOnDevice ? { name:"dataPoints",title:"设备定义",editorType:"bindDeviceList",valueType: y.objectArrayFromProps(props) } : { name:"dataPoints",title:"变量定义",editorType:"bindVarList",valueType: y.objectArrayFromProps(props) } } else { this.extendsProp = { name: "dataPoints", title: pointsTypeInfo.title, editorType: pointsTypeInfo.editorType, valueType: y.objectArrayFromProps(props) } } } clearCarousel() { console.log("clearCarousel") this.innerContainer.x = 0; this.innerContainer.y = 0; if (this.carouselTimer) { clearInterval(this.carouselTimer); this.carouselTimer = undefined; } createjs.Tween.removeTweens(this.innerContainer); } clearSubControls() { this.subControls.forEach(c => { c.destroy() }) this.innerContainer.removeAllChildren(); } getSubControlOwnShip() { const subControls = this.subControls; this.innerContainer.removeAllChildren(); this.subControls = [] return subControls; } checkControlPropertyChange() { if (this.api === undefined || this.subControlsPropsCache === this.cp.dataPoints) return; this.clearSubControls(); this.subControlsPropsCache = this.cp.dataPoints; const sampleData = this.containerControlData.sampleControlData; this.subControls = this.cp.dataPoints.map(c => { const ctrl = this.api!.createControl(sampleData); ctrl.setProperty(c) ctrl.initControl(this.api!); ctrl.setProperty(c) this.innerContainer.addChild(ctrl.getDisplayObject()) return ctrl; }) } startRun(): void { this.subControls.forEach(c => c.startRun()) this.checkCarousel(); } arrangeSubControls() { const p = this.p; const sampleData = this.containerControlData.sampleControlData; const positions = calcItemsPoisition( this.subControls.length, { width: sampleData.width, height: sampleData.height }, this.size, p ); this.subControls.forEach((c, i) => { const displayObject = c.getDisplayObject(); const position = positions[i]; displayObject.x = position.x; displayObject.y = position.y; c.size.height = position.height; c.size.width = position.width; c.reDraw() }) } checkMask() { if (this.p.overflowShow) { this.innerContainer.mask = undefined as any; } else { this.innerContainer.mask = this.maskShape; const g = this.maskShape.graphics; g.clear(); g.bf("yellow").drawRect(0, 0, this.size.width, this.size.height); } } checkCarousel() { if (!this.inPage() || this.subControls.length === 0) return; this.clearCarousel(); if (this.p.carouselInterval <= 0) return; let idx = 0; console.log("carousel set timer") this.carouselTimer = setInterval(() => { idx = (idx + 1) % this.subControls.length; const to = this.p.arrangement === "horizontal" ? { x: 0 - this.subControls[idx].getDisplayObject().x } : { y: 0 - this.subControls[idx].getDisplayObject().y }; // console.log("carousel to ", to); createjs.Tween.get(this.innerContainer, { override: true }).to(to, 500, createjs.Ease.cubicOut) }, this.p.carouselInterval * 1000); this.addDestroyCallback(() => { this.clearCarousel(); }) } reDraw(): void { // throw new Error("Method not implemented."); this.checkControlPropertyChange(); this.arrangeSubControls(); this.checkMask(); } getProperties(): EditorProperties { return [...this.props, this.extendsProp!]; } setPropertyMiss(missPropName: string, value: any): void { if (missPropName === "dataPoints") { this.cp.dataPoints = value; } } getControlData(): ContainerControlData { return { ...super.getControlData(), customName: this.customName, sampleControlData: this.containerControlData.sampleControlData, pointsTypeInfo: this.containerControlData.pointsTypeInfo } } } export const containerControlFactory = createControlFactory(PropDefine, ContainerControl)