Skip to content

Commit 83bdcd6

Browse files
author
Jonas Gossens
committed
🚧 Fix flickering pictures & mobile drag&drop
1 parent 914f19a commit 83bdcd6

File tree

4 files changed

+57
-40
lines changed

4 files changed

+57
-40
lines changed

src/react-chayns-gallery/component/Gallery.jsx

+41-31
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,14 @@ export default class Gallery extends Component {
5454
constructor(props) {
5555
super(props);
5656
this.galleryRef = React.createRef();
57+
this.state = { active: null, images: props.images, dropzone: null };
5758
}
5859

59-
componentDidUpdate(prevProps) {
60-
const { images } = this.props;
61-
if (prevProps.images !== images && this.selectedElement && this.lastDropzone) {
62-
this.selectedElement.classList.remove('cc__gallery__image--active');
63-
this.lastDropzone.classList.remove('cc__gallery__image--show_dropzone');
64-
this.selectedElement = null;
60+
componentWillUpdate(nextProps, nextState) {
61+
if (nextProps.images !== nextState.images) {
62+
// eslint-disable-next-line react/no-will-update-set-state
63+
this.setState({ images: nextProps.images });
6564
}
66-
return true;
6765
}
6866

6967
onDown = (event, index, image) => {
@@ -83,23 +81,18 @@ export default class Gallery extends Component {
8381
this.offsetY = this.pageYStart - this.selectedElementStartPosition.top;
8482

8583
document.addEventListener('mousemove', this.onMove);
86-
document.addEventListener('touchmove', this.onMove);
84+
document.addEventListener('touchmove', this.onMove, { passive: false });
8785
document.addEventListener('mouseup', this.onUp);
8886
document.addEventListener('touchend', this.onUp);
8987
document.addEventListener('touchcancel', this.onUp);
9088
};
9189

9290
onMove = (event) => {
93-
91+
event.preventDefault();
9492
const { pageX, pageY } = event.changedTouches ? event.changedTouches[0] : event;
9593
const { clientWidth: galleryWidth } = this.galleryRef.current;
9694
const { clientHeight: itemHeight, clientWidth: itemWidth } = event.target.parentElement.parentElement.parentElement;
9795

98-
// set selected element active
99-
if (!this.selectedElement.classList.contains('cc__gallery__image--active')) {
100-
this.selectedElement.classList.add('cc__gallery__image--active');
101-
}
102-
10396
// move item
10497
this.selectedElement.style.left = `${pageX - this.galleryOffsetX - this.offsetX}px`;
10598
this.selectedElement.style.top = `${pageY - this.galleryOffsetY - this.offsetY}px`;
@@ -111,24 +104,24 @@ export default class Gallery extends Component {
111104
const row = Math.floor(middleY / itemHeight);
112105
const column = Math.floor(middleX / itemWidth);
113106
this.newPosition = (row * itemsPerRow) + column;
107+
const { dropzone: oldDropzone } = this.state;
108+
const newDropzone = this.newPosition + (this.newPosition > this.index ? 1 : 0);
109+
if (oldDropzone !== newDropzone) {
110+
this.setState({ dropzone: newDropzone, active: this.index });
111+
}
114112

115113
// show corresponding dropzone
116114
let insertPosition = this.newPosition * 2; // dropzones and images are alternating
117115
if (this.newPosition > this.index) {
118116
insertPosition += 2;
119117
}
120118
const dropzone = this.galleryRef.current.children[insertPosition];
121-
if (this.lastDropzone && this.lastDropzone !== dropzone) {
122-
this.lastDropzone.classList.remove('cc__gallery__image--show_dropzone');
123-
}
124-
if (dropzone) {
125-
dropzone.classList.add('cc__gallery__image--show_dropzone');
126-
}
127119
this.lastDropzone = dropzone;
128120
};
129121

130122
onUp = () => {
131123
if (chayns.env.isApp || chayns.env.isMyChaynsApp) chayns.allowRefreshScroll();
124+
132125
document.removeEventListener('mousemove', this.onMove);
133126
document.removeEventListener('touchmove', this.onMove);
134127
document.removeEventListener('mouseup', this.onUp);
@@ -147,20 +140,27 @@ export default class Gallery extends Component {
147140
this.selectedElement.removeEventListener('transitionend', onTransitionEnd);
148141
this.selectedElement.classList.remove('cc__gallery__image--transition');
149142

143+
const image = images[this.index];
144+
const newArray = images.slice();
145+
newArray.splice(this.index, 1);
146+
newArray.splice(this.newPosition, 0, image);
147+
150148
if (onDragEnd) {
151-
const image = images[this.index];
152-
const newArray = images.slice();
153-
newArray.splice(this.index, 1);
154-
newArray.splice(this.newPosition, 0, image);
155149
onDragEnd(newArray);
156150
}
151+
152+
this.setState({ dropzone: null, active: null, images: newArray });
157153
}
158154
};
159155
this.transitionEnded = false;
160156
this.selectedElement.addEventListener('transitionend', onTransitionEnd);
161157
} else {
162158
this.selectedElement.classList.remove('cc__gallery__image--active');
163159
}
160+
// Enable scrolling.
161+
document.ontouchmove = function (e) {
162+
return true;
163+
};
164164
};
165165

166166
render() {
@@ -173,11 +173,11 @@ export default class Gallery extends Component {
173173
className,
174174
stopPropagation,
175175
onClick,
176-
images,
177176
} = this.props;
178177
const { style: propStyle } = this.props;
179178
const style = { ...propStyle };
180179
const defaultMode = !dragMode && !deleteMode;
180+
const { active, dropzone: dropzoneId, images } = this.state;
181181

182182
let styleHeight;
183183
if (defaultMode) {
@@ -193,11 +193,15 @@ export default class Gallery extends Component {
193193
}
194194
const numberOfImages = images.length;
195195

196-
const dropzone = key => (
197-
<div key={key} id={key} className="cc__gallery__image cc__gallery__image--dropzone">
196+
const dropzone = (key, show) => (
197+
<div
198+
key={key}
199+
id={key}
200+
className={classNames('cc__gallery__image cc__gallery__image--dropzone', { 'cc__gallery__image--show_dropzone': show })}
201+
>
198202
<ImageContainer>
199203
<div
200-
className="cc__gallery__image__dropzone chayns__background-color--101 chayns__border-color--300"
204+
className={classNames('cc__gallery__image__dropzone chayns__background-color--101 chayns__border-color--300')}
201205
/>
202206
</ImageContainer>
203207
</div>
@@ -216,7 +220,7 @@ export default class Gallery extends Component {
216220
>
217221
{
218222
dragMode
219-
? dropzone('dropzone')
223+
? dropzone('dropzone', dropzoneId === 0)
220224
: null
221225
}
222226
{
@@ -228,8 +232,10 @@ export default class Gallery extends Component {
228232
icon: 'ts-bars',
229233
className: 'cc__gallery__image__tool--drag',
230234
onDown: (event) => {
235+
event.preventDefault();
231236
this.onDown(event, index, image);
232237
},
238+
noScroll: true,
233239
});
234240
}
235241
if (deleteMode) {
@@ -242,7 +248,11 @@ export default class Gallery extends Component {
242248
}
243249

244250
return [
245-
<div className="cc__gallery__image" id={`image${index}`} key={`imageDiv${index}`}>
251+
<div
252+
className={classNames('cc__gallery__image', { 'cc__gallery__image--active': index === active })}
253+
id={`image${index}`}
254+
key={`imageDiv${index}`}
255+
>
246256
<ImageContainer
247257
tools={tools}
248258
>
@@ -263,7 +273,7 @@ export default class Gallery extends Component {
263273
</ImageContainer>
264274
</div>,
265275
dragMode
266-
? dropzone(`dropzone${index}`)
276+
? dropzone(`dropzone${index}`, dropzoneId === index + 1)
267277
: null,
268278
];
269279
}

src/react-chayns-gallery/component/Gallery.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
cursor: grab;
9797
&:active{
9898
cursor: grabbing;
99-
touch-action: none; // no scrolling
10099
}
101100
}
102101
}
@@ -114,6 +113,7 @@
114113
}
115114

116115
&--transition {
116+
will-change: top, left;
117117
transition: top 250ms ease, left 250ms ease;
118118
}
119119

src/react-chayns-gallery/component/Image.jsx

+13-6
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,19 @@ export default class Image extends PureComponent {
8484
this.setState({ imageUrl: image });
8585
}
8686
} else { // file
87-
const imageUrl = await getDataUrlFromFile(image);
88-
if (styleLandscape || stylePortrait) { // get dimensions if needed
89-
const metaData = await getImageMetaDataFromPreview(imageUrl);
90-
this.setState({ metaData, imageUrl });
91-
} else { // set only the image url
92-
this.setState({ imageUrl });
87+
const cacheId = `##FILE##${image.name}${image.lastModified}${image.size}`;
88+
if (Image.imageMetaData[cacheId]) { // use cache
89+
this.setState(Image.imageMetaData[cacheId]);
90+
} else { // get dataUrl and metaData and set cache
91+
const imageUrl = await getDataUrlFromFile(image);
92+
if (styleLandscape || stylePortrait) { // get dimensions if needed
93+
const metaData = await getImageMetaDataFromPreview(imageUrl);
94+
Image.imageMetaData[cacheId] = { metaData, imageUrl };
95+
this.setState({ metaData, imageUrl });
96+
} else { // set only the image url
97+
Image.imageMetaData[cacheId] = { imageUrl };
98+
this.setState({ imageUrl });
99+
}
93100
}
94101
}
95102
};

src/react-chayns-gallery/component/ImageContainer.scss

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
right: 0;
1313
}
1414

15-
&__tools{
16-
touch-action: none; // no scrolling
15+
&__tools {
1716
position: absolute;
1817
top: 0;
1918
right: 0;
2019
display: flex;
20+
touch-action: none; // no scrolling
2121
}
2222
}

0 commit comments

Comments
 (0)