Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

43 feature画布渲染html内容 #53

Merged
merged 22 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions packages/core/src/customs/html.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import Konva from 'konva';

export interface HtmlConfig extends Konva.ShapeConfig {
content?: HTMLElement;
}

const needForceStyle = (el: HTMLElement): boolean => {
const pos = window.getComputedStyle(el).position;
const ok = pos === 'absolute' || pos === 'relative';
return !ok;
};

export class Html extends Konva.Shape {
public className: string = 'Html';
public htmlDiv: HTMLDivElement = document.createElement('div');
public content?: HTMLElement;

constructor(config: HtmlConfig) {
super(config);

this.content = config.content;
if (this.content) {
this.htmlDiv.appendChild(this.content);
}
}

public _setAttr(key: any, val: any): void {
if (key === 'content') {
this.setContent(val);
} else {
super._setAttr(key, val);
}
}

public setContent(content: HTMLElement) {
this.content = content;
this.htmlDiv.innerHTML = '';
this.htmlDiv.appendChild(this.content);
}

public _sceneFunc(context: Konva.Context) {
const width = this.width();
const height = this.height();

context.beginPath();
context.rect(0, 0, width, height);
context.closePath();
context.fillStrokeShape(this);
this.addHtmlToStage();
this.handleTransform();
}

private addHtmlToStage() {
const stage = this.getStage();
const parent = stage?.container();

if (!parent || parent === this.htmlDiv.parentElement) {
return;
}

parent.appendChild(this.htmlDiv);

if (needForceStyle(parent)) {
parent.style.position = 'relative';
}

this.on('absoluteTransformChange', this.handleTransform);
this.on('dblclick', this.handleDblclick);
}

private handleDblclick() {
this.htmlDiv.style.pointerEvents = 'auto';
}

private handleTransform() {
const tr = this.getAbsoluteTransform();
const attrs = tr.decompose();

this.htmlDiv.style.position = 'absolute';
this.htmlDiv.style.top = '0px';
this.htmlDiv.style.left = '0px';
this.htmlDiv.style.width = `${this.width() * attrs.scaleX}px`;
this.htmlDiv.style.height = `${this.height() * attrs.scaleY}px`;
this.htmlDiv.style.transform = `translate(${attrs.x}px, ${attrs.y}px) rotate(${attrs.rotation}deg)`;
this.htmlDiv.style.transformOrigin = 'top left';
this.htmlDiv.style.pointerEvents = 'none';
this.htmlDiv.style.opacity = `${this.opacity()}`;

const { style, ...restProps } = this.attrs.divProps || {};
Object.assign(this.htmlDiv.style, style);
Object.assign(this.htmlDiv, restProps);
}

_remove(): void {
super._remove();
this.htmlDiv.parentElement?.removeChild(this.htmlDiv);
this.off('absoluteTransformChange', this.handleTransform);
this.off('dblclick', this.handleDblclick);
}
}

export default Html;
34 changes: 34 additions & 0 deletions packages/core/src/customs/iframe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Html, { HtmlConfig } from './html';

export type IframeConfig = Omit<Partial<HtmlConfig>, 'content'> & {
src?: string;
};

export class Iframe extends Html {
public className: string = 'Iframe';
public iframeElement: HTMLIFrameElement = document.createElement('iframe');

constructor(config: IframeConfig) {
super(config);

this.iframeElement.src = config.src ?? '';
this.iframeElement.style.border = 'none';
this.iframeElement.style.width = '100%';
this.iframeElement.style.height = '100%';
this.iframeElement.style.display = 'block';
this.iframeElement.style.margin = '0';
this.iframeElement.style.boxSizing = 'border-box';

super.setContent(this.iframeElement);
}

public _setAttr(key: any, val: any): void {
if (key === 'src' && this.iframeElement) {
this.iframeElement.src = val;
} else {
super._setAttr(key, val);
}
}
}

export default Iframe;
2 changes: 2 additions & 0 deletions packages/core/src/customs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './html';
export * from './iframe';
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as Konva } from 'konva';
export * from './app';
export * from './types';
export * as util from './utils';
export * from './customs';
65 changes: 65 additions & 0 deletions packages/tools/src/html/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Html, HtmlConfig, Tool, ToolEvent, ToolHooks, util } from '@pictode/core';

export type HtmlToolConfig = Partial<HtmlConfig>;

export interface HtmlToolOptions {
config?: HtmlToolConfig;
hooks?: ToolHooks;
}

export class HtmlTool implements Tool {
public name: string = 'htmlTool';
public config?: HtmlToolConfig;
public hooks?: ToolHooks;
private html: Html | null = null;
private startPointer: util.Point = new util.Point(0, 0);

constructor({ config, hooks }: HtmlToolOptions) {
this.config = config;
this.hooks = hooks;
}

public mousedown({ app }: ToolEvent) {
if (this.html) {
return;
}
this.startPointer.clone(app.pointer);
this.html = new Html({
strokeScaleEnabled: false,
...this.config,
});
this.html.setPosition(this.startPointer);
this.html.width(0);
this.html.height(0);
app.add(this.html);
this.hooks?.onStartDrawing?.(app, this.html);
}

public mousemove({ app }: ToolEvent) {
if (!this.html) {
return;
}
this.html.setPosition(
new util.Point(Math.min(this.startPointer.x, app.pointer.x), Math.min(this.startPointer.y, app.pointer.y))
);
this.html.width(Math.abs(app.pointer.x - this.startPointer.x));
this.html.height(Math.abs(app.pointer.y - this.startPointer.y));
app.render();
}

public mouseup({ app, pointer }: ToolEvent) {
if (!this.html) {
return;
}
if (this.startPointer.eq(pointer)) {
this.html?.destroy();
this.html = null;
return;
}
this.hooks?.onCompleteDrawing?.(app, this.html);
this.html = null;
this.startPointer.setXY(0, 0);
}
}

export default HtmlTool;
66 changes: 66 additions & 0 deletions packages/tools/src/iframe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Iframe, IframeConfig, Tool, ToolEvent, ToolHooks, util } from '@pictode/core';

export type IframeToolConfig = Partial<IframeConfig>;

export interface IframeToolOptions {
config?: IframeToolConfig;
hooks?: ToolHooks;
}

export class IframeTool implements Tool {
public name: string = 'iframeTool';
public config?: IframeToolConfig;
public hooks?: ToolHooks;
private iframe: Iframe | null = null;
private startPointer: util.Point = new util.Point(0, 0);

constructor({ config, hooks }: IframeToolOptions) {
this.config = config;
this.hooks = hooks;
}

public mousedown({ app }: ToolEvent) {
if (this.iframe) {
return;
}

this.startPointer.clone(app.pointer);
this.iframe = new Iframe({
strokeScaleEnabled: false,
...this.config,
});
this.iframe.setPosition(this.startPointer);
this.iframe.width(0);
this.iframe.height(0);
app.add(this.iframe);
this.hooks?.onStartDrawing?.(app, this.iframe);
}

public mousemove({ app }: ToolEvent) {
if (!this.iframe) {
return;
}
this.iframe.setPosition(
new util.Point(Math.min(this.startPointer.x, app.pointer.x), Math.min(this.startPointer.y, app.pointer.y))
);
this.iframe.width(Math.abs(app.pointer.x - this.startPointer.x));
this.iframe.height(Math.abs(app.pointer.y - this.startPointer.y));
app.render();
}

public mouseup({ app, pointer }: ToolEvent) {
if (!this.iframe) {
return;
}
if (this.startPointer.eq(pointer)) {
this.iframe?.destroy();
this.iframe = null;
return;
}
this.hooks?.onCompleteDrawing?.(app, this.iframe);
this.iframe = null;
this.startPointer.setXY(0, 0);
}
}

export default IframeTool;
8 changes: 4 additions & 4 deletions packages/tools/src/image/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Konva, Tool, ToolEvent, ToolHooks, util } from '@pictode/core';

export type ImageConfig = Partial<Konva.ImageConfig> & { image: HTMLImageElement };
export type ImageToolConfig = Partial<Konva.ImageConfig> & { image: HTMLImageElement };

export interface ImageToolOptions {
config: ImageConfig;
config: ImageToolConfig;
hooks?: ToolHooks;
}

export class ImageTool implements Tool<ImageConfig> {
export class ImageTool implements Tool<ImageToolConfig> {
public name = 'imageTool';
public config: ImageConfig;
public config: ImageToolConfig;
public hooks?: ToolHooks;
private image: Konva.Image | null = null;
private isCompleted: boolean = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export * from './rect';
export * from './select';
export * from './text';
export * from './eraser';
export * from './html';
export * from './iframe';
4 changes: 2 additions & 2 deletions pictode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script
src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_28449_48.34f83713a1d0bd3fb2ca87c936cccf2e.js"></script>
src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_28449_50.b49bc49973e273e145957454257bb6ef.js"></script>
<script
src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_28449_48.34f83713a1d0bd3fb2ca87c936cccf2e.es5.js"></script>
src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_28449_50.b49bc49973e273e145957454257bb6ef.es5.js"></script>
</body>

</html>
3 changes: 2 additions & 1 deletion pictode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@pictode/tools": "workspace:^",
"@pictode/utils": "workspace:^",
"@pictode/vue-aide": "workspace:^",
"codemirror": "^6.0.1",
"cssnano": "^6.0.1",
"vanilla-colorful": "^0.7.2",
"vue": "^3.3.4",
Expand All @@ -31,13 +32,13 @@
"@rollup/plugin-typescript": "^11.0.0",
"@types/three": "^0.150.0",
"@vitejs/plugin-vue": "^4.0.0",
"ant-design-vue": "^4.0.6",
"autoprefixer": "^10.4.14",
"gh-pages": "^5.0.0",
"postcss": "^8.4.27",
"postcss-import": "^15.1.0",
"sass": "^1.63.6",
"tailwind-scrollbar": "^3.0.5",
"ant-design-vue": "^4.0.6",
"tailwindcss": "^3.3.3",
"typescript": "^4.9.3",
"vite": "^4.0.0",
Expand Down
6 changes: 2 additions & 4 deletions pictode/src/form/Container.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ const props = withDefaults(
}
);

const emits = defineEmits<{
(event: 'change', model: FormValue): void;
}>();
const emits = defineEmits<(event: 'change', model: FormValue) => void>();

const formState = injectStrict(FormStateKey);

const { config, prop, model } = toRefs(props);

const name = computed<string | number>(() => config.value.name || '');
const name = computed<string | number>(() => config.value.name ?? '');

const itemProp = computed<string>(() => {
let result: string | number = '';
Expand Down
4 changes: 1 addition & 3 deletions pictode/src/form/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ const handleSubmit = async (): Promise<FormValue> => {
await formRef.value?.validate();
return toRaw(formModel.value);
} catch (invalidFields: any) {
const error: string[] = [];
Object;
throw new Error(error.join('<br>'));
throw new Error();
}
};

Expand Down
4 changes: 1 addition & 3 deletions pictode/src/form/fields/Color.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ const props = withDefaults(
}
);

const emits = defineEmits<{
(event: 'change', props: string, value: string): void;
}>();
const emits = defineEmits<(event: 'change', props: string, value: string) => void>();

const { model, prop } = toRefs(props);
const colors = ref<string>(prop?.value && model?.value?.[prop?.value]);
Expand Down
4 changes: 1 addition & 3 deletions pictode/src/form/fields/RadioGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ const props = withDefaults(
}
);

const emits = defineEmits<{
(event: 'change', prop: string, value: T): void;
}>();
const emits = defineEmits<(event: 'change', prop: string, value: T) => void>();

const { model, prop } = toRefs(props);
const value = ref<T>(prop?.value && model?.value?.[prop?.value]);
Expand Down
Loading