Skip to content

Commit 801cf7b

Browse files
Merge pull request #41 from tolgamizrakci/development
canvas snap grid & styling update
2 parents 038cfa4 + 9cdc8fe commit 801cf7b

File tree

6 files changed

+321
-180
lines changed

6 files changed

+321
-180
lines changed

src/components/KonvaStage.jsx

Lines changed: 87 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
import React, { Component, createRef, Fragment } from 'react';
1+
import React, { Component, createRef, Fragment } from "react";
22
// import PropTypes from 'prop-types';
33
import {
4-
Stage, Layer, Group, Label, Text, Rect, Transformer,
5-
} from 'react-konva';
6-
import Rectangle from './Rectangle.jsx';
4+
Stage,
5+
Layer,
6+
Line,
7+
Group,
8+
Label,
9+
Text,
10+
Rect,
11+
Transformer
12+
} from "react-konva";
13+
import Rectangle from "./Rectangle.jsx";
714

815
class KonvaStage extends Component {
916
constructor(props) {
1017
super(props);
1118
this.state = {
1219
stageWidth: 1000,
1320
stageHeight: 1000,
21+
blockSnapSize: 5,
22+
grid: [],
23+
gridStroke: 1
1424
};
1525
}
1626

@@ -19,70 +29,124 @@ class KonvaStage extends Component {
1929
// here we should add listener for "container" resize
2030
// take a look here https://developers.google.com/web/updates/2016/10/resizeobserver
2131
// for simplicity I will just listen window resize
22-
window.addEventListener('resize', this.checkSize);
32+
window.addEventListener("resize", this.checkSize);
33+
this.createGrid();
2334
}
2435

2536
componentWillUnmount() {
26-
window.removeEventListener('resize', this.checkSize);
37+
window.removeEventListener("resize", this.checkSize);
2738
}
2839

2940
checkSize = () => {
3041
const width = this.container.offsetWidth;
3142
const height = this.container.offsetHeight;
3243
this.setState({
3344
stageWidth: width,
34-
stageHeight: height,
45+
stageHeight: height
3546
});
3647
};
3748

38-
handleStageMouseDown = (e) => {
49+
handleStageMouseDown = e => {
3950
// // clicked on stage - clear selection
4051
if (e.target === e.target.getStage()) {
4152
// add functionality for allowing no focusChild
42-
console.log('user clicked on canvas:');
53+
console.log("user clicked on canvas:");
4354
return;
4455
}
4556
// // clicked on transformer - do nothing
46-
const clickedOnTransformer = e.target.getParent().className === 'Transformer';
57+
const clickedOnTransformer =
58+
e.target.getParent().className === "Transformer";
4759
if (clickedOnTransformer) {
48-
console.log('user clicked on transformer');
60+
console.log("user clicked on transformer");
61+
console.log("HELLOOOO", e.target.getParent().className);
4962
return;
5063
}
5164

5265
// find clicked rect by its name
5366
const rectChildId = e.target.attrs.childId;
54-
console.log('user clicked on child rectangle with Id: ', rectChildId);
67+
console.log("user clicked on child rectangle with Id: ", rectChildId);
5568
this.props.changeFocusChild({ childId: rectChildId });
5669
this.props.changeComponentFocusChild({
5770
componentId: this.props.focusComponent.id,
58-
childId: rectChildId,
71+
childId: rectChildId
72+
});
73+
};
74+
75+
createGrid = () => {
76+
let output = [];
77+
for (let i = 0; i < this.state.stageWidth / this.state.blockSnapSize; i++) {
78+
output.push(
79+
<Line
80+
points={[
81+
Math.round(i * this.state.blockSnapSize) + 0.5,
82+
0,
83+
Math.round(i * this.state.blockSnapSize) + 0.5,
84+
this.state.stageHeight
85+
]}
86+
stroke={"#ddd"}
87+
strokeWidth={this.state.gridStroke}
88+
key={i + "vertical"}
89+
/>
90+
);
91+
}
92+
for (
93+
let j = 0;
94+
j < this.state.stageHeight / this.state.blockSnapSize;
95+
j++
96+
) {
97+
output.push(
98+
<Line
99+
points={[
100+
0,
101+
Math.round(j * this.state.blockSnapSize),
102+
this.state.stageWidth,
103+
Math.round(j * this.state.blockSnapSize)
104+
]}
105+
stroke={"#ddd"}
106+
strokeWidth={this.state.gridStroke}
107+
key={j + "horizontal"}
108+
/>
109+
);
110+
}
111+
console.log("calling function to render grid");
112+
this.setState({
113+
grid: output
59114
});
60115
};
61116

62117
render() {
63118
const {
64-
components, handleTransform, focusComponent, focusChild,
119+
components,
120+
handleTransform,
121+
focusComponent,
122+
focusChild
65123
} = this.props;
66124

67125
return (
68126
<div
69127
style={{
70-
width: '100%',
71-
height: '100%',
128+
width: "100%",
129+
height: "100%"
72130
}}
73-
ref={(node) => {
131+
ref={node => {
74132
this.container = node;
75133
}}
76134
>
77135
<Stage
78-
ref={(node) => {
136+
className={"canvasStage"}
137+
ref={node => {
79138
this.stage = node;
80139
}}
81140
onMouseDown={this.handleStageMouseDown}
82141
width={this.state.stageWidth}
83142
height={this.state.stageHeight}
84143
>
85-
<Layer>
144+
<Layer
145+
ref={node => {
146+
this.layer = node;
147+
}}
148+
>
149+
{this.state.grid}
86150
{components
87151
.find(comp => comp.id === focusComponent.id)
88152
.childrenArray.map((child, i) => (
@@ -103,10 +167,13 @@ class KonvaStage extends Component {
103167
title={child.componentName + child.childId}
104168
handleTransform={handleTransform}
105169
draggable={true}
170+
blockSnapSize={this.state.blockSnapSize}
106171
/>
107172
))
108173
.sort(
109-
(rectA, rectB) => rectA.props.width * rectA.props.height < rectB.props.width * rectB.props.height,
174+
(rectA, rectB) =>
175+
rectA.props.width * rectA.props.height <
176+
rectB.props.width * rectB.props.height
110177
)
111178
// reasoning for the sort:
112179
// Konva determines zIndex (which rect is clicked on if rects overlap) based on rendering order

src/components/Rectangle.jsx

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,54 @@
1-
import React, { Component } from 'react';
2-
import {
3-
Rect, Group, Label, Text,
4-
} from 'react-konva';
5-
import TransformerComponent from './TransformerComponent.jsx';
6-
import GrandchildRectangle from './GrandchildRectangle.jsx';
1+
import React, { Component } from "react";
2+
import { Rect, Group, Label, Text } from "react-konva";
3+
import TransformerComponent from "./TransformerComponent.jsx";
4+
import GrandchildRectangle from "./GrandchildRectangle.jsx";
75

86
class Rectangle extends Component {
97
getComponentColor(componentId) {
10-
const color = this.props.components.find(comp => comp.id == componentId).color;
8+
const color = this.props.components.find(comp => comp.id == componentId)
9+
.color;
1110
return color;
1211
}
1312

14-
handleResize(componentId, childId, target) {
13+
handleResize(componentId, childId, target, blockSnapSize) {
1514
const focChild = this.props.components
1615
.find(comp => comp.id === componentId)
1716
.childrenArray.find(child => child.childId === childId);
1817

1918
const transformation = {
20-
width: target.width() * target.scaleX(),
21-
height: target.height() * target.scaleY(),
19+
// width:
20+
// Math.round((target.width() * target.scaleX()) / blockSnapSize) *
21+
// blockSnapSize,
22+
// height:
23+
// Math.round((target.height() * target.scaleY()) / blockSnapSize) *
24+
// blockSnapSize,
25+
// x: target.x() + focChild.position.x,
26+
// y: target.y() + focChild.position.y
27+
28+
width:
29+
Math.round((target.width() * target.scaleX()) / blockSnapSize) *
30+
blockSnapSize,
31+
height:
32+
Math.round((target.height() * target.scaleY()) / blockSnapSize) *
33+
blockSnapSize,
2234
x: target.x() + focChild.position.x,
23-
y: target.y() + focChild.position.y,
35+
y: target.y() + focChild.position.y
2436
};
2537

2638
this.props.handleTransform(componentId, childId, transformation);
2739
}
2840

29-
handleDrag(componentId, childId, target) {
41+
handleDrag(componentId, childId, target, blockSnapSize) {
3042
console.log(target);
43+
console.log("blockSnapSize", blockSnapSize);
3144

3245
const transformation = {
33-
x: target.x(),
34-
y: target.y(),
46+
// x: target.x(),
47+
// y: target.y()
48+
x: Math.round(target.x() / blockSnapSize) * blockSnapSize,
49+
y: Math.round(target.y() / blockSnapSize) * blockSnapSize
3550
};
51+
console.log(transformation);
3652
this.props.handleTransform(componentId, childId, transformation);
3753
}
3854

@@ -52,6 +68,7 @@ class Rectangle extends Component {
5268
focusChild,
5369
components,
5470
draggable,
71+
blockSnapSize
5572
} = this.props;
5673

5774
// the Group is responsible for dragging of all children
@@ -65,11 +82,13 @@ class Rectangle extends Component {
6582
scaleY={scaleY}
6683
width={width}
6784
height={height}
68-
onDragEnd={event => this.handleDrag(componentId, childId, event.target)}
85+
onDragEnd={event =>
86+
this.handleDrag(componentId, childId, event.target, blockSnapSize)
87+
}
6988
>
7089
<Rect
7190
name={`${childId}`}
72-
className={'childRect'}
91+
className={"childRect"}
7392
x={0}
7493
y={0}
7594
childId={childId}
@@ -82,39 +101,47 @@ class Rectangle extends Component {
82101
stroke={this.getComponentColor(childComponentId)}
83102
// fill={color}
84103
// opacity={0.8}
85-
onTransformEnd={event => this.handleResize(componentId, childId, event.target)}
104+
onTransformEnd={event =>
105+
this.handleResize(componentId, childId, event.target, blockSnapSize)
106+
}
86107
strokeWidth={4}
87108
strokeScaleEnabled={false}
88109
draggable={false}
89-
dashEnabled={childId === '-1'} // dash line only enabled for pseudochild
90-
dash={[10, 3]} // 10px dashes with 3px gaps
110+
fill={childId === "-1" ? "white" : null}
111+
shadowBlur={childId === "-1" ? 6 : null}
112+
// dashEnabled={childId === "-1"} // dash line only enabled for pseudochild
113+
// dash={[10, 3]} // 10px dashes with 3px gaps
91114
/>
92115
<Label>
93116
<Text
94-
fontStyle={'bold'}
95-
fontVariant={'small-caps'}
117+
fontStyle={"bold"}
118+
fontVariant={"small-caps"}
96119
// pseudochild's label should look different than normal children:
97-
text={childId === '-1' ? title.slice(0, title.length - 2) : title}
98-
fill={childId === '-1' ? this.getComponentColor(childComponentId) : 'white'}
99-
fontSize={childId === '-1' ? 15 : 10}
120+
text={childId === "-1" ? title.slice(0, title.length - 2) : title}
121+
fill={
122+
childId === "-1"
123+
? this.getComponentColor(childComponentId)
124+
: "black"
125+
}
126+
fontSize={childId === "-1" ? 15 : 10}
100127
x={4}
101-
y={childId === '-1' ? -15 : 5}
128+
y={childId === "-1" ? -15 : 5}
102129
/>
103130
</Label>
104-
{focusChild
105-
&& focusChild.childId === childId
106-
&& draggable && (
131+
{focusChild &&
132+
focusChild.childId === childId &&
133+
draggable && (
107134
<TransformerComponent
108135
focusChild={focusChild}
109-
rectClass={'childRect'}
136+
rectClass={"childRect"}
110137
anchorSize={8}
111-
color={'grey'}
138+
color={"grey"}
112139
/>
113-
)}
114-
{childId !== '-1'
115-
&& components
140+
)}
141+
{childId !== "-1" &&
142+
components
116143
.find(comp => comp.title === childComponentName)
117-
.childrenArray.filter(child => child.childId !== '-1')
144+
.childrenArray.filter(child => child.childId !== "-1")
118145
.map((grandchild, i) => (
119146
<GrandchildRectangle
120147
key={i}
@@ -128,8 +155,12 @@ class Rectangle extends Component {
128155
y={grandchild.position.y * (height / window.innerHeight)}
129156
scaleX={1}
130157
scaleY={1}
131-
width={grandchild.position.width * (width / (window.innerWidth / 2))}
132-
height={grandchild.position.height * (height / window.innerHeight)}
158+
width={
159+
grandchild.position.width * (width / (window.innerWidth / 2))
160+
}
161+
height={
162+
grandchild.position.height * (height / window.innerHeight)
163+
}
133164
// title={child.componentName + child.childId}
134165
/>
135166
))}

0 commit comments

Comments
 (0)