Skip to content

Commit d39d2db

Browse files
sunflatmugi-unohidakatsuya
committed
Add Vue components
Co-authored-by: mugi-uno <mugi.uno@gmail.com> Co-authored-by: Katsuya HIDAKA <hidakatsuya@gmail.com>
1 parent ff5c450 commit d39d2db

116 files changed

Lines changed: 7274 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<template>
2+
<svg
3+
width="1"
4+
height="1"
5+
viewbox="0 0 1 1"
6+
class="th-font-preloader-canvas"
7+
>
8+
<text
9+
v-for="(family, index) in fontFamilies"
10+
:key="index"
11+
width="1"
12+
height="1"
13+
:font-family="family"
14+
>
15+
_
16+
</text>
17+
</svg>
18+
</template>
19+
20+
<script lang="ts">
21+
import Vue from 'vue';
22+
23+
export default Vue.extend({
24+
name: 'FontPreloader',
25+
computed: {
26+
fontFamilies () {
27+
return [
28+
'IPAGothic',
29+
'IPAPGothic',
30+
'IPAMincho',
31+
'IPAPMincho'
32+
];
33+
}
34+
}
35+
});
36+
</script>
37+
38+
<style scoped>
39+
.th-font-preloader-canvas {
40+
position: absolute;
41+
left: -1000px;
42+
pointer-events: none;
43+
visibility: hidden;
44+
}
45+
</style>
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
<template>
2+
<g>
3+
<rect
4+
width="100%"
5+
height="100%"
6+
class="th-layer-item-dragger"
7+
@pointermove="drag"
8+
@pointerup="finish"
9+
/>
10+
<g
11+
v-if="isStarted"
12+
:transform="reportTransform"
13+
>
14+
<ItemOutline
15+
:item-type="itemType"
16+
:bounding-points="outlineBounds"
17+
/>
18+
</g>
19+
</g>
20+
</template>
21+
22+
<script lang="ts">
23+
import Vue, { PropType } from 'vue';
24+
import { BoundsTransformer } from '../lib/bounds-transformer';
25+
import { operator, report } from '../store';
26+
import ItemOutline from './items/ItemOutline.vue';
27+
import { Coords, BoundingPoints, ItemType } from '@/types';
28+
29+
type Data = {
30+
itemType: ItemType | null;
31+
itemBounds: BoundingPoints | null;
32+
initialPointer: Coords | null;
33+
outlineBounds: BoundingPoints | null;
34+
};
35+
36+
class UnexpectedStateError extends Error {
37+
constructor () {
38+
super();
39+
this.name = 'UnexpectedStateError';
40+
}
41+
};
42+
43+
export default Vue.extend({
44+
name: 'LayerItemDragger',
45+
components: {
46+
ItemOutline
47+
},
48+
props: {
49+
reportTransform: {
50+
type: String,
51+
required: true
52+
},
53+
transformSvgPoint: {
54+
type: Function as PropType<(point: Coords) => Coords>,
55+
required: true
56+
}
57+
},
58+
data (): Data {
59+
return {
60+
itemType: null,
61+
itemBounds: null,
62+
initialPointer: null,
63+
outlineBounds: null
64+
};
65+
},
66+
computed: {
67+
isStarted (): boolean {
68+
return this.initialPointer !== null;
69+
},
70+
draggerState: () => operator.state.itemDragger
71+
},
72+
methods: {
73+
start (e: MouseEvent) {
74+
const point = this.transformSvgPoint(e);
75+
76+
if (!this.draggerState.itemUid) throw new UnexpectedStateError();
77+
78+
const item = report.getters.findItem(this.draggerState.itemUid);
79+
80+
this.itemType = item.type;
81+
this.itemBounds = this.convertToReportCoords(report.getters.itemBounds(item.uid));
82+
this.outlineBounds = { ...this.itemBounds };
83+
this.initialPointer = { x: point.x, y: point.y };
84+
},
85+
drag (e: MouseEvent) {
86+
if (!this.isStarted) this.start(e);
87+
88+
const point = this.transformSvgPoint(e);
89+
90+
if (!this.itemBounds || !this.outlineBounds || !this.initialPointer) throw new UnexpectedStateError();
91+
92+
const deltaPointer = {
93+
x: point.x - this.initialPointer.x,
94+
y: point.y - this.initialPointer.y
95+
};
96+
97+
this.outlineBounds = {
98+
x1: this.itemBounds.x1 + deltaPointer.x,
99+
y1: this.itemBounds.y1 + deltaPointer.y,
100+
x2: this.itemBounds.x2 + deltaPointer.x,
101+
y2: this.itemBounds.y2 + deltaPointer.y
102+
};
103+
},
104+
finish () {
105+
if (!this.isStarted) {
106+
this.cancel();
107+
return;
108+
}
109+
if (!this.outlineBounds) throw new UnexpectedStateError();
110+
111+
this.moveItemTo(this.convertToLocalCoords(this.outlineBounds));
112+
113+
operator.actions.finishItemDrag();
114+
},
115+
cancel () {
116+
operator.actions.finishItemDrag();
117+
},
118+
moveItemTo (bounds: BoundingPoints) {
119+
if (!this.draggerState.itemUid || !this.itemType) throw new UnexpectedStateError();
120+
121+
const payload = { uid: this.draggerState.itemUid, bounds };
122+
123+
switch (this.itemType) {
124+
case 'rect': report.actions.moveRectItemTo(payload); break;
125+
case 'ellipse': report.actions.moveEllipseItemTo(payload); break;
126+
case 'line': report.actions.moveLineItemTo(payload); break;
127+
case 'image-block': report.actions.moveImageBlockItemTo(payload); break;
128+
case 'image': report.actions.moveImageItemTo(payload); break;
129+
case 'text': report.actions.moveTextItemTo(payload); break;
130+
case 'text-block': report.actions.moveTextBlockItemTo(payload); break;
131+
case 'stack-view': report.actions.moveStackViewItemTo(payload); break;
132+
default:
133+
throw new Error('Not Implemented');
134+
}
135+
},
136+
convertToReportCoords (boundingPoints: BoundingPoints): BoundingPoints {
137+
const localTranslation = this.draggerState.translation;
138+
if (!localTranslation) throw new UnexpectedStateError();
139+
140+
return new BoundsTransformer(boundingPoints).expand(localTranslation).toBPoints();
141+
},
142+
convertToLocalCoords (boundingPoints: BoundingPoints): BoundingPoints {
143+
const localTranslation = this.draggerState.translation;
144+
if (!localTranslation) throw new UnexpectedStateError();
145+
146+
return new BoundsTransformer(boundingPoints).relativeFrom(localTranslation).toBPoints();
147+
}
148+
}
149+
});
150+
</script>
151+
152+
<style scoped>
153+
.th-layer-item-dragger {
154+
stroke: none;
155+
fill: none;
156+
pointer-events: visible;
157+
cursor: move;
158+
}
159+
</style>
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<template>
2+
<g>
3+
<rect
4+
width="100%"
5+
height="100%"
6+
class="th-layer-item-drawer"
7+
@pointermove="draw"
8+
@pointerup="finish"
9+
/>
10+
<g
11+
v-if="isStarted"
12+
:transform="reportTransform"
13+
>
14+
<ItemOutline
15+
:item-type="drawerState.itemType"
16+
:bounding-points="outlineBounds"
17+
/>
18+
</g>
19+
</g>
20+
</template>
21+
22+
<script lang="ts">
23+
import Vue, { PropType } from 'vue';
24+
import { BoundsTransformer } from '../lib/bounds-transformer';
25+
import { operator, report, editor } from '../store';
26+
import ItemOutline from './items/ItemOutline.vue';
27+
import { BoundingPoints, Coords } from '@/types';
28+
29+
type Data = {
30+
outlineBounds: BoundingPoints | null;
31+
};
32+
33+
class UnexpectedStateError extends Error {
34+
constructor () {
35+
super();
36+
this.name = 'UnexpectedStateError';
37+
}
38+
};
39+
40+
export default Vue.extend({
41+
name: 'LayerItemDrawer',
42+
components: {
43+
ItemOutline
44+
},
45+
props: {
46+
reportTransform: {
47+
type: String,
48+
required: true
49+
},
50+
transformSvgPoint: {
51+
type: Function as PropType<(point: Coords) => Coords>,
52+
required: true
53+
}
54+
},
55+
data (): Data {
56+
return {
57+
outlineBounds: null
58+
};
59+
},
60+
computed: {
61+
isStarted (): boolean {
62+
return this.outlineBounds !== null;
63+
},
64+
drawerState: () => operator.state.itemDrawer
65+
},
66+
methods: {
67+
start (e: MouseEvent) {
68+
const point = this.transformSvgPoint(e);
69+
70+
this.outlineBounds = {
71+
x1: point.x,
72+
y1: point.y,
73+
x2: point.x,
74+
y2: point.y
75+
};
76+
},
77+
draw (e: MouseEvent) {
78+
const point = this.transformSvgPoint(e);
79+
80+
if (!this.isStarted) this.start(e);
81+
if (!this.outlineBounds) throw new UnexpectedStateError();
82+
83+
this.outlineBounds.x2 = point.x;
84+
this.outlineBounds.y2 = point.y;
85+
},
86+
finish () {
87+
if (!this.isStarted || this.isOutlineEmpty()) {
88+
this.cancel();
89+
return;
90+
}
91+
92+
if (!this.outlineBounds) throw new UnexpectedStateError();
93+
94+
this.drawNewItem(this.convertToLocalCoords(this.outlineBounds));
95+
96+
operator.actions.finishItemDraw();
97+
editor.actions.activateTool({ tool: 'select' });
98+
},
99+
cancel () {
100+
operator.actions.finishItemDraw();
101+
},
102+
isOutlineEmpty () {
103+
if (this.outlineBounds) {
104+
const box = new BoundsTransformer(this.outlineBounds).toBBox();
105+
return box.width < 4 && box.height < 4;
106+
} else {
107+
return true;
108+
}
109+
},
110+
drawNewItem (bounds: BoundingPoints) {
111+
const { itemType, targetType, targetUid } = this.drawerState;
112+
113+
if (!itemType || !targetType || !targetUid) throw new UnexpectedStateError();
114+
115+
const payload = { targetType, targetUid, bounds };
116+
117+
switch (itemType) {
118+
case 'rect': report.actions.drawNewRectItem(payload); break;
119+
case 'ellipse': report.actions.drawNewEllipseItem(payload); break;
120+
case 'line': report.actions.drawNewLineItem(payload); break;
121+
case 'text': report.actions.drawNewTextItem(payload); break;
122+
case 'text-block': report.actions.drawNewTextBlockItem(payload); break;
123+
case 'image-block': report.actions.drawNewImageBlockItem(payload); break;
124+
case 'stack-view': report.actions.drawNewStackViewItem(payload); break;
125+
default:
126+
throw new Error(`Invalid itemType: ${itemType}`);
127+
}
128+
},
129+
convertToLocalCoords (bPoints: BoundingPoints): BoundingPoints {
130+
const localTranslation = this.drawerState.translation;
131+
if (!localTranslation) throw new UnexpectedStateError();
132+
133+
return new BoundsTransformer(bPoints).relativeFrom(localTranslation).toBPoints();
134+
}
135+
}
136+
});
137+
</script>
138+
139+
<style scoped>
140+
.th-layer-item-drawer {
141+
stroke: none;
142+
fill: none;
143+
pointer-events: visible;
144+
cursor: crosshair;
145+
}
146+
</style>

0 commit comments

Comments
 (0)