Refactored tool system
This commit is contained in:
parent
8d42e6536f
commit
0e7b797a9d
18 changed files with 529 additions and 435 deletions
|
@ -1,434 +0,0 @@
|
||||||
<style>
|
|
||||||
.ide {
|
|
||||||
width: 100vw;
|
|
||||||
height: calc(100vh - 50px);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 300px 1fr 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ide-left, .ide-mid, .ide-right {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ide-left {
|
|
||||||
border-right: var(--border-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ide-right {
|
|
||||||
border-left: var(--border-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ide-mid {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
|
|
||||||
import pkg from 'paper';
|
|
||||||
const { paper } = pkg;
|
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
import EditButton from '$lib/page/EditButton.svelte';
|
|
||||||
import Color from './Color.svelte';
|
|
||||||
import { Group } from "paper/dist/paper-core";
|
|
||||||
import { group_outros } from "svelte/internal";
|
|
||||||
|
|
||||||
let tools = [
|
|
||||||
'edit',
|
|
||||||
'pan',
|
|
||||||
'select',
|
|
||||||
'group',
|
|
||||||
'ungroup',
|
|
||||||
'resize',
|
|
||||||
'rotate',
|
|
||||||
'deleter',
|
|
||||||
'node',
|
|
||||||
'up',
|
|
||||||
'down',
|
|
||||||
'import',
|
|
||||||
'export',
|
|
||||||
]
|
|
||||||
|
|
||||||
let mode = 'edit';
|
|
||||||
let colorType = 'stroke';
|
|
||||||
|
|
||||||
let fillColor = '#446699ff';
|
|
||||||
let strokeColor = '#000000ff';
|
|
||||||
|
|
||||||
let darkStroke = '#d8d8d8';
|
|
||||||
let white = 'white';
|
|
||||||
|
|
||||||
let nodeDist = 25;
|
|
||||||
let grabDist = 15;
|
|
||||||
|
|
||||||
let color = strokeColor;
|
|
||||||
let stroke = 12;
|
|
||||||
|
|
||||||
let origin = new paper.Point([0,0]);
|
|
||||||
|
|
||||||
let viewGroup, innerGroup, canvas, mainPath, lastPoint, file, files, download;
|
|
||||||
|
|
||||||
let importFile = () => {
|
|
||||||
file.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
let getBase64 = (filee) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(filee);
|
|
||||||
reader.onload = e => {
|
|
||||||
let preview = e.target.result;
|
|
||||||
paper.project.importSVG(preview, function (item) {
|
|
||||||
innerGroup.addChild(item);
|
|
||||||
recurseChild(innerGroup);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let exportFile = () => {
|
|
||||||
var data = new Blob(['<svg>' + innerGroup.exportSVG({asString: true}) + '</svg>'], {type: 'image/svg'});
|
|
||||||
|
|
||||||
var url = window.URL.createObjectURL(data);
|
|
||||||
|
|
||||||
download.href = url;
|
|
||||||
download.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
let setMode = (modeSet) => {
|
|
||||||
if (modeSet)
|
|
||||||
mode = modeSet;
|
|
||||||
|
|
||||||
if (mode == 'group') {
|
|
||||||
group();
|
|
||||||
} else if (mode == 'ungroup') {
|
|
||||||
ungroup();
|
|
||||||
} else if (mode == 'import') {
|
|
||||||
importFile();
|
|
||||||
} else if (mode == 'export') {
|
|
||||||
exportFile();
|
|
||||||
} else if (mode == 'deleter') {
|
|
||||||
deleter();
|
|
||||||
} else if (mode == 'up') {
|
|
||||||
layerUp();
|
|
||||||
} else if (mode == 'down') {
|
|
||||||
layerDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
let setColorMode = (modeSet) => {
|
|
||||||
if (modeSet)
|
|
||||||
colorType = modeSet;
|
|
||||||
|
|
||||||
color = (modeSet == 'stroke') ? strokeColor : fillColor;
|
|
||||||
|
|
||||||
return colorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
let setColor = ([colorIn, strokeIn]) => {
|
|
||||||
color = colorIn;
|
|
||||||
stroke = strokeIn / 5;
|
|
||||||
|
|
||||||
if (colorType == 'stroke') {
|
|
||||||
strokeColor = color
|
|
||||||
} else {
|
|
||||||
fillColor = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!paper.project || !paper.project.selectedItems) return;
|
|
||||||
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
if (colorType == 'stroke') {
|
|
||||||
item.strokeColor = color
|
|
||||||
} else {
|
|
||||||
item.fillColor = color;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let initPath = () => {
|
|
||||||
mainPath = new paper.Path();
|
|
||||||
|
|
||||||
mainPath.strokeColor = strokeColor;
|
|
||||||
mainPath.fillColor = fillColor;
|
|
||||||
mainPath.strokeWidth = stroke;
|
|
||||||
mainPath.strokeCap = 'butt';
|
|
||||||
mainPath.strokeJoin = 'bevel';
|
|
||||||
|
|
||||||
innerGroup.addChild(mainPath);
|
|
||||||
|
|
||||||
recurseChild(innerGroup);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseDown = (event) => {
|
|
||||||
if (mode == 'edit') {
|
|
||||||
initPath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let layerDown = () => {
|
|
||||||
paper.project.selectedItems.reverse().forEach(item => {
|
|
||||||
item.sendToBack();
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let layerUp = () => {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
item.bringToFront();
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let group = () => {
|
|
||||||
var group = new paper.Group(paper.project.selectedItems);
|
|
||||||
innerGroup.addChild(group);
|
|
||||||
};
|
|
||||||
|
|
||||||
let ungroup = () => {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
if (!item.children || item.className != 'Group' || item == innerGroup) return;
|
|
||||||
item.selected = false;
|
|
||||||
item.children.forEach(child => {
|
|
||||||
innerGroup.addChild(child);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let deleter = () => {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
console.log(item);
|
|
||||||
item.remove();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseDownInner = (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
console.log(event.target);
|
|
||||||
|
|
||||||
var target = event.target;
|
|
||||||
|
|
||||||
while (target.parent != innerGroup) {
|
|
||||||
target = target.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(target);
|
|
||||||
|
|
||||||
if (mode == 'select') {
|
|
||||||
target.selected = !target.selected;
|
|
||||||
} else if (mode == 'node') {
|
|
||||||
var nearestPoint = target.getNearestPoint(event.point);
|
|
||||||
|
|
||||||
if (nearestPoint.getDistance(event.point) > nodeDist) return;
|
|
||||||
|
|
||||||
target.segments.forEach(segment => {
|
|
||||||
segment.selected = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
let closestPoint = target.segments[0];
|
|
||||||
let closestDist = 10000;
|
|
||||||
|
|
||||||
target.segments.forEach(segment => {
|
|
||||||
let dist = segment.point.getDistance(nearestPoint);
|
|
||||||
if (dist < closestDist) {
|
|
||||||
closestDist = dist;
|
|
||||||
closestPoint = segment.point;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let newPoint;
|
|
||||||
|
|
||||||
if (nearestPoint.getDistance(closestPoint) > grabDist) {
|
|
||||||
newPoint = target.divideAt(target.getLocationOf(nearestPoint));
|
|
||||||
} else {
|
|
||||||
newPoint = closestPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
newPoint.selected = true;
|
|
||||||
} else if (mode == 'resize' || mode == 'rotate') {
|
|
||||||
target.selected = !target.selected;
|
|
||||||
target.bounds.selected = target.selected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseDrag = (event) => {
|
|
||||||
if (mode == 'pan') {
|
|
||||||
viewGroup.position = viewGroup.position.add(event.delta);
|
|
||||||
} else if (mode == 'edit') {
|
|
||||||
lastPoint = event.point;
|
|
||||||
|
|
||||||
mainPath.add(event.point);
|
|
||||||
} else if (mode == 'select' || mode == 'node') {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
if ((mode == 'select' && item.parent != innerGroup)) return;
|
|
||||||
|
|
||||||
if (mode == 'node') {
|
|
||||||
if (item.className == 'Path') {
|
|
||||||
item.segments.forEach(segment => {
|
|
||||||
if (segment.selected)
|
|
||||||
segment.point = segment.point.add(event.delta)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item.position = item.position.add(event.delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
} else if (mode == 'resize') {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
var nearestPoint = event.point;
|
|
||||||
|
|
||||||
if (!item.bounds.selected) return;
|
|
||||||
|
|
||||||
let seg = [
|
|
||||||
item.bounds.topLeft,
|
|
||||||
item.bounds.topRight,
|
|
||||||
item.bounds.bottomLeft,
|
|
||||||
item.bounds.bottomRight,
|
|
||||||
item.bounds.topCenter,
|
|
||||||
item.bounds.bottomCenter,
|
|
||||||
item.bounds.leftCenter,
|
|
||||||
item.bounds.rightCenter
|
|
||||||
];
|
|
||||||
|
|
||||||
let segOpp = [
|
|
||||||
item.bounds.bottomRight,
|
|
||||||
item.bounds.bottomLeft,
|
|
||||||
item.bounds.topRight,
|
|
||||||
item.bounds.topLeft,
|
|
||||||
item.bounds.bottomCenter,
|
|
||||||
item.bounds.topCenter,
|
|
||||||
item.bounds.rightCenter,
|
|
||||||
item.bounds.leftCenter
|
|
||||||
]
|
|
||||||
|
|
||||||
let closestPoint = seg[0];
|
|
||||||
let closestDist = 10000;
|
|
||||||
let i = -1;
|
|
||||||
|
|
||||||
seg.forEach((segment,index) => {
|
|
||||||
let dist = segment.getDistance(nearestPoint);
|
|
||||||
if (dist < closestDist) {
|
|
||||||
closestDist = dist;
|
|
||||||
closestPoint = segOpp[index];
|
|
||||||
i = index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (closestDist < nodeDist) {
|
|
||||||
var signX = (i == 1 || i == 3 || i == 7) ? 1 : -1;
|
|
||||||
var signY = (i == 1 || i == 0 || i == 4) ? -1 : 1;
|
|
||||||
if (i > 5) {
|
|
||||||
item.scale(1 + signX * event.delta.x / item.bounds.width, 1, closestPoint);
|
|
||||||
} else if (i > 3) {
|
|
||||||
item.scale(1, 1 + signY * event.delta.y / item.bounds.height, closestPoint);
|
|
||||||
} else {
|
|
||||||
item.scale(1 + signX * event.delta.x / item.bounds.width, 1 + signY * event.delta.y / item.bounds.height, closestPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (mode == 'rotate') {
|
|
||||||
paper.project.selectedItems.forEach(item => {
|
|
||||||
if (!item.bounds.selected) return;
|
|
||||||
var rotAngle = event.point.subtract(item.bounds.center).angle - event.point.add(event.delta).subtract(item.bounds.center).angle;
|
|
||||||
item.rotate(-rotAngle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseUp = (event) => {
|
|
||||||
if (mode == 'edit') {
|
|
||||||
if (mainPath.lastSegment.point.getDistance(mainPath.firstSegment.point) < nodeDist) {
|
|
||||||
mainPath.closePath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseDragInner = (event) => {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let recurseChild = (parent) => {
|
|
||||||
if (!parent.children || parent.children.length == 0) {
|
|
||||||
parent.onMouseDrag = mouseDragInner;
|
|
||||||
parent.onDoubleClick = mouseDownInner;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
parent.onMouseDrag = () => {};
|
|
||||||
parent.onDoubleClick = () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.children.forEach(child => {
|
|
||||||
if (child == parent) return;
|
|
||||||
recurseChild(child);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let initView = () => {
|
|
||||||
let rect = new paper.Rectangle(0,0,480,360);
|
|
||||||
|
|
||||||
let path = new paper.Path.Rectangle(rect);
|
|
||||||
path.fillColor = 'white';
|
|
||||||
|
|
||||||
let pathOut = new paper.Path.Rectangle(rect);
|
|
||||||
|
|
||||||
pathOut.strokeColor = darkStroke;
|
|
||||||
pathOut.strokeWidth = '3';
|
|
||||||
|
|
||||||
innerGroup = new paper.Group([]);
|
|
||||||
|
|
||||||
viewGroup = new paper.Group([path,innerGroup,pathOut]);
|
|
||||||
|
|
||||||
/*paper.project.importSVG("/logo.svg", function (item) {
|
|
||||||
innerGroup.addChild(item);
|
|
||||||
recurseChild(innerGroup);
|
|
||||||
})*/
|
|
||||||
|
|
||||||
viewGroup.onMouseDrag = mouseDrag;
|
|
||||||
viewGroup.onMouseDown = mouseDown;
|
|
||||||
viewGroup.onMouseUp = mouseUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (!canvas) return;
|
|
||||||
|
|
||||||
paper.setup(canvas);
|
|
||||||
|
|
||||||
initView();
|
|
||||||
initPath();
|
|
||||||
|
|
||||||
console.log(paper.view);
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class='ide'>
|
|
||||||
<div class='ide-left'>
|
|
||||||
{#each tools as tool}
|
|
||||||
<EditButton bindMode={setMode} modeIn={mode} mode={tool} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
<div class='ide-mid'>
|
|
||||||
<canvas class='canvas' resize bind:this={canvas}></canvas>
|
|
||||||
</div>
|
|
||||||
<div class='ide-right'>
|
|
||||||
<EditButton bindMode={setColorMode} modeIn={colorType} mode={'stroke'} />
|
|
||||||
<EditButton bindMode={setColorMode} modeIn={colorType} mode={'fill'} />
|
|
||||||
<Color bindColor={setColor} color={color} />
|
|
||||||
<input type="file" style="display:none" bind:files on:change={() => getBase64(files[0])} bind:this={file}>
|
|
||||||
<a download="export.svg" bind:this={download} hidden></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
266
src/lib/vector/Env.svelte
Normal file
266
src/lib/vector/Env.svelte
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
<style>
|
||||||
|
.ide {
|
||||||
|
width: 100vw;
|
||||||
|
height: calc(100vh - 50px);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 300px 1fr 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ide-left, .ide-mid, .ide-right {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ide-left {
|
||||||
|
border-right: var(--border-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ide-right {
|
||||||
|
border-left: var(--border-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ide-mid {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
import pkg from 'paper';
|
||||||
|
const { paper } = pkg;
|
||||||
|
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
import EditButton from '$lib/page/EditButton.svelte';
|
||||||
|
import Color from './Color.svelte';
|
||||||
|
import { Group } from "paper/dist/paper-core";
|
||||||
|
import { group_outros } from "svelte/internal";
|
||||||
|
|
||||||
|
let tools = [
|
||||||
|
'edit',
|
||||||
|
'pan',
|
||||||
|
'select',
|
||||||
|
'group',
|
||||||
|
'ungroup',
|
||||||
|
'resize',
|
||||||
|
'rotate',
|
||||||
|
'deleter',
|
||||||
|
'node',
|
||||||
|
'up',
|
||||||
|
'down',
|
||||||
|
'import',
|
||||||
|
'export',
|
||||||
|
]
|
||||||
|
|
||||||
|
let toolData = {};
|
||||||
|
|
||||||
|
tools.forEach(async tool => {
|
||||||
|
toolData[tool] = await import(`./tools/${tool}.js`);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
let viewGroup, canvas, mainPath, lastPoint, file, files, download, settings;
|
||||||
|
|
||||||
|
let darkStroke = '#000000';
|
||||||
|
|
||||||
|
let mode = 'edit';
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
colorType: 'stroke',
|
||||||
|
|
||||||
|
fill: {
|
||||||
|
color: '#446699ff',
|
||||||
|
stroke: '#000000ff'
|
||||||
|
},
|
||||||
|
|
||||||
|
color: '#000000ff',
|
||||||
|
|
||||||
|
stroke: 12,
|
||||||
|
|
||||||
|
innerGroup: null,
|
||||||
|
|
||||||
|
viewGroup: null,
|
||||||
|
|
||||||
|
mainPath: null,
|
||||||
|
|
||||||
|
nodeDist: 45,
|
||||||
|
|
||||||
|
grabDist: 15,
|
||||||
|
|
||||||
|
doc: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
let getBase64 = (filee) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(filee);
|
||||||
|
reader.onload = e => {
|
||||||
|
let preview = e.target.result;
|
||||||
|
paper.project.importSVG(preview, function (item) {
|
||||||
|
settings.innerGroup.addChild(item);
|
||||||
|
recurseChild(settings.innerGroup);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let execFunc = (obj, val, args) => {
|
||||||
|
obj = obj.toolData;
|
||||||
|
if (obj[val]) {
|
||||||
|
let result = obj[val]({
|
||||||
|
...args,
|
||||||
|
...settings,
|
||||||
|
delta: args.delta,
|
||||||
|
point: args.point,
|
||||||
|
target: args.target,
|
||||||
|
selectedItems: paper.project.selectedItems
|
||||||
|
});
|
||||||
|
settings = result || settings;
|
||||||
|
recurseChild(settings.innerGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let origin = new paper.Point([0,0]);
|
||||||
|
|
||||||
|
|
||||||
|
let setMode = (modeSet) => {
|
||||||
|
if (modeSet)
|
||||||
|
mode = modeSet;
|
||||||
|
|
||||||
|
execFunc(toolData[mode],'run',[])
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let setColorMode = (modeSet) => {
|
||||||
|
if (modeSet)
|
||||||
|
settings.colorType = modeSet;
|
||||||
|
|
||||||
|
color = (modeSet == 'stroke') ? settings.fill.stroke : settings.fill.color;
|
||||||
|
|
||||||
|
return settings.colorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let setColor = ([colorIn, strokeIn]) => {
|
||||||
|
settings.color = colorIn;
|
||||||
|
settings.stroke = strokeIn / 5;
|
||||||
|
|
||||||
|
if (settings.colorType == 'stroke') {
|
||||||
|
settings.fill.stroke = settings.color
|
||||||
|
} else {
|
||||||
|
settings.fill.color = settings.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!paper.project || !paper.project.selectedItems) return;
|
||||||
|
|
||||||
|
paper.project.selectedItems.forEach(item => {
|
||||||
|
if (settings.colorType == 'stroke') {
|
||||||
|
item.strokeColor = settings.color
|
||||||
|
} else {
|
||||||
|
item.fillColor = settings.color;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mouseEvent = (type) => {
|
||||||
|
return (event) => {
|
||||||
|
execFunc(toolData[mode],type,event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mouseEventInner = (type) => {
|
||||||
|
return (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
var target = event.target;
|
||||||
|
|
||||||
|
while (target.parent != settings.innerGroup && target.parent != settings.viewGroup && target.parent) {
|
||||||
|
target = target.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.target = target;
|
||||||
|
|
||||||
|
execFunc(toolData[mode],type,event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let recurseChild = (parent) => {
|
||||||
|
if (!parent.children || parent.children.length == 0) {
|
||||||
|
parent.onMouseDrag = mouseEventInner('mouseDragInner');
|
||||||
|
parent.onDoubleClick = mouseEventInner('doubleClickInner');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
parent.onMouseDrag = () => {};
|
||||||
|
parent.onDoubleClick = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.forEach(child => {
|
||||||
|
if (child == parent) return;
|
||||||
|
recurseChild(child);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let initView = () => {
|
||||||
|
let rect = new paper.Rectangle(0,0,480,360);
|
||||||
|
|
||||||
|
let path = new paper.Path.Rectangle(rect);
|
||||||
|
path.fillColor = 'white';
|
||||||
|
|
||||||
|
let pathOut = new paper.Path.Rectangle(rect);
|
||||||
|
|
||||||
|
pathOut.strokeColor = darkStroke;
|
||||||
|
pathOut.strokeWidth = '3';
|
||||||
|
|
||||||
|
settings.innerGroup = new paper.Group([]);
|
||||||
|
|
||||||
|
settings.viewGroup = new paper.Group([path,settings.innerGroup,pathOut]);
|
||||||
|
|
||||||
|
/*paper.project.importSVG("/logo.svg", function (item) {
|
||||||
|
innerGroup.addChild(item);
|
||||||
|
recurseChild(innerGroup);
|
||||||
|
})*/
|
||||||
|
|
||||||
|
settings.viewGroup.onMouseDrag = mouseEvent('mouseDrag');
|
||||||
|
settings.viewGroup.onMouseDown = mouseEvent('mouseDown');
|
||||||
|
settings.viewGroup.onMouseUp = mouseEvent('mouseUp');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
paper.setup(canvas);
|
||||||
|
|
||||||
|
initView();
|
||||||
|
|
||||||
|
console.log(paper.view);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class='ide'>
|
||||||
|
<div class='ide-left'>
|
||||||
|
{#each tools as tool}
|
||||||
|
<EditButton bindMode={setMode} modeIn={mode} mode={tool} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class='ide-mid'>
|
||||||
|
<canvas class='canvas' resize bind:this={canvas}></canvas>
|
||||||
|
</div>
|
||||||
|
<div class='ide-right'>
|
||||||
|
<EditButton bindMode={setColorMode} modeIn={settings.colorType} mode={'stroke'} />
|
||||||
|
<EditButton bindMode={setColorMode} modeIn={settings.colorType} mode={'fill'} />
|
||||||
|
<Color bindColor={setColor} color={settings.color} />
|
||||||
|
<input type="file" style="display:none" bind:files on:change={() => getBase64(files[0])} bind:this={settings.doc.file}>
|
||||||
|
<a download="export.svg" bind:this={settings.doc.download} hidden></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
10
src/lib/vector/tools/deleter.js
Normal file
10
src/lib/vector/tools/deleter.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ selectedItems }) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
item.remove();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
10
src/lib/vector/tools/down.js
Normal file
10
src/lib/vector/tools/down.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ selectedItems }) => {
|
||||||
|
selectedItems.reverse().forEach(item => {
|
||||||
|
item.sendToBack();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
38
src/lib/vector/tools/edit.js
Normal file
38
src/lib/vector/tools/edit.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import pkg from 'paper';
|
||||||
|
const { paper } = pkg;
|
||||||
|
|
||||||
|
let lastPoint;
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
mouseDown: (settings) => {
|
||||||
|
let { innerGroup, mainPath, fill, stroke } = settings;
|
||||||
|
mainPath = new paper.Path();
|
||||||
|
|
||||||
|
mainPath.strokeColor = fill.stroke;
|
||||||
|
mainPath.fillColor = fill.color;
|
||||||
|
|
||||||
|
mainPath.strokeWidth = stroke;
|
||||||
|
mainPath.strokeCap = 'butt';
|
||||||
|
mainPath.strokeJoin = 'bevel';
|
||||||
|
|
||||||
|
innerGroup.addChild(mainPath);
|
||||||
|
|
||||||
|
settings.mainPath = mainPath;
|
||||||
|
return settings;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseDrag: ( {mainPath, point}) => {
|
||||||
|
lastPoint = point;
|
||||||
|
|
||||||
|
mainPath.add(point);
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseUp: ( {mainPath, nodeDist }) => {
|
||||||
|
if (mainPath.lastSegment.point.getDistance(mainPath.firstSegment.point) < nodeDist) {
|
||||||
|
mainPath.closePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
13
src/lib/vector/tools/export.js
Normal file
13
src/lib/vector/tools/export.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ innerGroup, doc }) => {
|
||||||
|
var data = new Blob(['<svg>' + innerGroup.exportSVG({asString: true}) + '</svg>'], {type: 'image/svg'});
|
||||||
|
|
||||||
|
var url = window.URL.createObjectURL(data);
|
||||||
|
|
||||||
|
doc.download.href = url;
|
||||||
|
doc.download.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
12
src/lib/vector/tools/group.js
Normal file
12
src/lib/vector/tools/group.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
import pkg from 'paper';
|
||||||
|
const { paper } = pkg;
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ selectedItems, innerGroup }) => {
|
||||||
|
var group = new paper.Group(selectedItems);
|
||||||
|
innerGroup.addChild(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
7
src/lib/vector/tools/import.js
Normal file
7
src/lib/vector/tools/import.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
let toolData = {
|
||||||
|
run: ({ doc }) => {
|
||||||
|
doc.file.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
45
src/lib/vector/tools/node.js
Normal file
45
src/lib/vector/tools/node.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
let toolData = {
|
||||||
|
doubleClickInner: (event) => {
|
||||||
|
var nearestPoint = event.target.getNearestPoint(event.point);
|
||||||
|
|
||||||
|
if (nearestPoint.getDistance(event.point) > event.nodeDist) return;
|
||||||
|
|
||||||
|
event.target.segments.forEach(segment => {
|
||||||
|
segment.selected = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
let closestPoint = event.target.segments[0];
|
||||||
|
let closestDist = 10000;
|
||||||
|
|
||||||
|
event.target.segments.forEach(segment => {
|
||||||
|
let dist = segment.point.getDistance(nearestPoint);
|
||||||
|
if (dist < closestDist) {
|
||||||
|
closestDist = dist;
|
||||||
|
closestPoint = segment.point;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let newPoint;
|
||||||
|
|
||||||
|
if (nearestPoint.getDistance(closestPoint) > event.grabDist) {
|
||||||
|
newPoint = event.target.divideAt(event.target.getLocationOf(nearestPoint));
|
||||||
|
} else {
|
||||||
|
newPoint = closestPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPoint.selected = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseDrag : ( {selectedItems, delta} ) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
if (item.className == 'Path') {
|
||||||
|
item.segments.forEach(segment => {
|
||||||
|
if (segment.selected)
|
||||||
|
segment.point = segment.point.add(delta)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
7
src/lib/vector/tools/pan.js
Normal file
7
src/lib/vector/tools/pan.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
let toolData = {
|
||||||
|
mouseDrag: ( { viewGroup, delta } ) => {
|
||||||
|
viewGroup.position = viewGroup.position.add(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
64
src/lib/vector/tools/resize.js
Normal file
64
src/lib/vector/tools/resize.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
let toolData = {
|
||||||
|
doubleClickInner: ({ target }) => {
|
||||||
|
target.selected = !target.selected;
|
||||||
|
target.bounds.selected = target.selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseDrag: ( {selectedItems, point, delta, nodeDist} ) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
var nearestPoint = point;
|
||||||
|
|
||||||
|
if (!item.bounds.selected) return;
|
||||||
|
|
||||||
|
|
||||||
|
let seg = [
|
||||||
|
item.bounds.topLeft,
|
||||||
|
item.bounds.topRight,
|
||||||
|
item.bounds.bottomLeft,
|
||||||
|
item.bounds.bottomRight,
|
||||||
|
item.bounds.topCenter,
|
||||||
|
item.bounds.bottomCenter,
|
||||||
|
item.bounds.leftCenter,
|
||||||
|
item.bounds.rightCenter
|
||||||
|
];
|
||||||
|
|
||||||
|
let segOpp = [
|
||||||
|
item.bounds.bottomRight,
|
||||||
|
item.bounds.bottomLeft,
|
||||||
|
item.bounds.topRight,
|
||||||
|
item.bounds.topLeft,
|
||||||
|
item.bounds.bottomCenter,
|
||||||
|
item.bounds.topCenter,
|
||||||
|
item.bounds.rightCenter,
|
||||||
|
item.bounds.leftCenter
|
||||||
|
]
|
||||||
|
|
||||||
|
let closestPoint = seg[0];
|
||||||
|
let closestDist = 10000;
|
||||||
|
let i = -1;
|
||||||
|
|
||||||
|
seg.forEach((segment,index) => {
|
||||||
|
let dist = segment.getDistance(nearestPoint);
|
||||||
|
if (dist < closestDist) {
|
||||||
|
closestDist = dist;
|
||||||
|
closestPoint = segOpp[index];
|
||||||
|
i = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closestDist < nodeDist) {
|
||||||
|
var signX = (i == 1 || i == 3 || i == 7) ? 1 : -1;
|
||||||
|
var signY = (i == 1 || i == 0 || i == 4) ? -1 : 1;
|
||||||
|
if (i > 5) {
|
||||||
|
item.scale(1 + signX * delta.x / item.bounds.width, 1, closestPoint);
|
||||||
|
} else if (i > 3) {
|
||||||
|
item.scale(1, 1 + signY * delta.y / item.bounds.height, closestPoint);
|
||||||
|
} else {
|
||||||
|
item.scale(1 + signX * delta.x / item.bounds.width, 1 + signY * delta.y / item.bounds.height, closestPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
16
src/lib/vector/tools/rotate.js
Normal file
16
src/lib/vector/tools/rotate.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
let toolData = {
|
||||||
|
doubleClickInner: ({ target }) => {
|
||||||
|
target.selected = !target.selected;
|
||||||
|
target.bounds.selected = target.selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseDrag: ( {selectedItems, point, delta} ) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
if (!item.bounds.selected) return;
|
||||||
|
var rotAngle = point.subtract(item.bounds.center).angle - point.add(delta).subtract(item.bounds.center).angle;
|
||||||
|
item.rotate(-rotAngle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
16
src/lib/vector/tools/select.js
Normal file
16
src/lib/vector/tools/select.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
let toolData = {
|
||||||
|
doubleClickInner: ({ target }) => {
|
||||||
|
target.selected = !target.selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseDragInner: ( {selectedItems, delta, innerGroup} ) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
if ((item.parent != innerGroup)) return;
|
||||||
|
|
||||||
|
item.position = item.position.add(delta)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
14
src/lib/vector/tools/ungroup.js
Normal file
14
src/lib/vector/tools/ungroup.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ selectedItems, innerGroup }) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
if (!item.children || item.className != 'Group' || item == innerGroup) return;
|
||||||
|
item.selected = false;
|
||||||
|
item.children.forEach(child => {
|
||||||
|
innerGroup.addChild(child);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
10
src/lib/vector/tools/up.js
Normal file
10
src/lib/vector/tools/up.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
let toolData = {
|
||||||
|
run: ({ selectedItems }) => {
|
||||||
|
selectedItems.forEach(item => {
|
||||||
|
item.bringToFront();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { toolData };
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import Env from '$lib/ide/Env.svelte'
|
import Env from '$lib/vector/Env.svelte'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Env />
|
<Env />
|
Loading…
Reference in a new issue