Skip to content
GitLab
Explorer
Connexion
Navigation principale
Rechercher ou aller à…
Projet
M
mydressin-front
Gestion
Activité
Membres
Labels
Programmation
Tickets
0
Tableaux des tickets
Jalons
Wiki
Jira
Code
Requêtes de fusion
0
Dépôt
Branches
Validations
Étiquettes
Graphe du dépôt
Comparer les révisions
Extraits de code
Compilation
Pipelines
Jobs
Planifications de pipeline
Artéfacts
Déploiement
Releases
Registre de paquets
Opération
Environnements
Modules Terraform
Surveillance
Incidents
Service d'assistance
Analyse
Données d'analyse des chaînes de valeur
Contributor analytics
Données d'analyse CI/CD
Données d'analyse du dépôt
Expériences du modèle
Aide
Aide
Support
Documentation de GitLab
Comparer les forfaits GitLab
Forum de la communauté
Contribuer à GitLab
Donner votre avis
Raccourcis clavier
?
Extraits de code
Groupes
Projets
mydressin
mydressin-front
Validations
4e679ebe
Valider
4e679ebe
rédigé
il y a un an
par
salaheddine zidani
Parcourir les fichiers
Options
Téléchargements
Correctifs
Plain Diff
add pop-up to crop image
parent
ccfd84bb
Branches
Branches contenant la validation
1 requête de fusion
!125
MYD-312/ add pop-up to crop image
Pipeline
#2403
réussi avec l'étape
in 4 minutes et 27 secondes
Modifications
2
Pipelines
1
Masquer les modifications d'espaces
En ligne
Côte à côte
Affichage de
2 fichiers modifiés
src/shared/sections/media/view/crop-image/EditImageModal.tsx
+186
-0
186 ajouts, 0 suppression
src/shared/sections/media/view/crop-image/EditImageModal.tsx
src/shared/sections/media/view/crop-image/cropImage.ts
+68
-0
68 ajouts, 0 suppression
src/shared/sections/media/view/crop-image/cropImage.ts
avec
254 ajouts
et
0 suppression
src/shared/sections/media/view/crop-image/EditImageModal.tsx
0 → 100644
+
186
−
0
Voir le fichier @
4e679ebe
import
React
,
{
useState
,
useCallback
,
useEffect
}
from
'
react
'
;
import
Cropper
from
'
react-easy-crop
'
;
import
{
Modal
,
Button
,
Typography
,
Grid
,
Slider
,
Stack
,
ButtonGroup
,
FormControl
}
from
'
@mui/material
'
;
import
{
IMedia
}
from
'
@/shared/types/media
'
;
import
ZoomOutIcon
from
'
@mui/icons-material/ZoomOut
'
;
import
ZoomInIcon
from
'
@mui/icons-material/ZoomIn
'
;
import
RotateLeftIcon
from
'
@mui/icons-material/RotateLeft
'
;
import
RotateRightIcon
from
'
@mui/icons-material/RotateRight
'
;
import
{
Area
}
from
'
react-easy-crop
'
;
import
{
getCroppedImg
}
from
'
./cropImage
'
;
type
ImageEditorProps
=
{
open
:
boolean
;
onClose
:
()
=>
void
;
image
:
IMedia
|
undefined
;
setEditedImage
:
(
image
:
File
|
null
)
=>
void
;
};
const
aspectRatios
=
[
{
value
:
4
/
3
,
label
:
'
4:3
'
},
{
value
:
16
/
9
,
label
:
'
16:9
'
},
{
value
:
1
,
label
:
'
1:1
'
},
{
value
:
3
/
2
,
label
:
'
3:2
'
},
{
value
:
undefined
,
label
:
'
Free
'
},
];
const
EditImageModal
:
React
.
FC
<
ImageEditorProps
>
=
({
open
,
onClose
,
image
,
setEditedImage
})
=>
{
const
[
crop
,
setCrop
]
=
useState
({
x
:
0
,
y
:
0
});
const
[
zoom
,
setZoom
]
=
useState
(
1
);
const
[
rotation
,
setRotation
]
=
useState
(
0
);
const
[
croppedAreaPixels
,
setCroppedAreaPixels
]
=
useState
<
Area
|
null
>
(
null
);
const
[
imageUrl
,
setImageUrl
]
=
useState
(
''
);
const
[
aspectRatio
,
setAspectRatio
]
=
useState
<
number
|
undefined
>
(
4
/
3
);
const
[
originalAspectRatio
,
setOriginalAspectRatio
]
=
useState
<
number
|
undefined
>
(
undefined
);
const
[
uploadedImage
,
setUploadedImage
]
=
useState
<
string
|
null
>
(
null
);
useEffect
(()
=>
{
const
extractUrl
=
(
url
:
string
)
=>
{
const
match
=
url
.
match
(
/Optional
\[(
.*
)\]
/
);
return
match
?
match
[
1
]
:
url
;
};
if
(
image
?.
url
&&
!
uploadedImage
)
{
const
imgUrl
=
extractUrl
(
image
.
url
);
setImageUrl
(
imgUrl
);
const
img
=
new
Image
();
img
.
src
=
imgUrl
;
img
.
onload
=
()
=>
{
setOriginalAspectRatio
(
img
.
width
/
img
.
height
);
};
}
},
[
image
,
uploadedImage
]);
const
onCropComplete
=
useCallback
((
croppedArea
:
Area
,
croppedAreaPixels
:
Area
)
=>
{
setCroppedAreaPixels
(
croppedAreaPixels
);
},
[]);
const
handleSave
=
useCallback
(
async
()
=>
{
if
(
croppedAreaPixels
&&
imageUrl
)
{
try
{
const
croppedImage
=
await
getCroppedImg
(
imageUrl
,
croppedAreaPixels
,
rotation
);
if
(
croppedImage
)
{
const
file
=
new
File
([
croppedImage
],
'
editedImage.png
'
,
{
type
:
'
image/png
'
});
setEditedImage
(
file
);
onClose
();
}
}
catch
(
e
)
{
console
.
error
(
e
);
}
}
},
[
croppedAreaPixels
,
rotation
,
imageUrl
,
onClose
,
setEditedImage
]);
const
handleAspectRatioChange
=
(
newRatio
:
number
|
undefined
)
=>
{
setAspectRatio
(
newRatio
);
};
const
handleZoomChange
=
(
value
:
number
)
=>
{
setZoom
(
Math
.
min
(
Math
.
max
(
value
,
1
),
3
));
// Ensure the zoom value stays between 1 and 3
};
const
handleRotationChange
=
(
value
:
number
)
=>
{
setRotation
(((
value
%
360
)
+
360
)
%
360
);
// Ensure the rotation value stays between 0 and 360
};
const
handleFileChange
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
file
=
event
.
target
.
files
?.[
0
];
if
(
file
)
{
const
reader
=
new
FileReader
();
reader
.
onload
=
()
=>
{
setUploadedImage
(
reader
.
result
as
string
);
setImageUrl
(
reader
.
result
as
string
);
const
img
=
new
Image
();
img
.
src
=
reader
.
result
as
string
;
img
.
onload
=
()
=>
{
setOriginalAspectRatio
(
img
.
width
/
img
.
height
);
};
};
reader
.
readAsDataURL
(
file
);
}
};
return
(
<
Modal
open
=
{
open
}
onClose
=
{
onClose
}
>
<
Grid
container
justifyContent
=
"center"
alignItems
=
"center"
style
=
{
{
width
:
'
65%
'
,
maxWidth
:
'
70%
'
,
position
:
'
absolute
'
,
top
:
'
50%
'
,
left
:
'
50%
'
,
transform
:
'
translate(-50%, -50%)
'
,
backgroundColor
:
'
white
'
,
padding
:
'
20px
'
,
borderRadius
:
'
15px
'
}
}
>
<
Grid
item
xs
=
{
12
}
sx
=
{
{
mb
:
3
}
}
>
<
Typography
variant
=
"h5"
align
=
"center"
gutterBottom
>
Modifier image
</
Typography
>
</
Grid
>
<
Grid
item
xs
=
{
12
}
style
=
{
{
height
:
400
,
position
:
'
relative
'
}
}
>
{
imageUrl
&&
(
<
Cropper
image
=
{
imageUrl
}
crop
=
{
crop
}
zoom
=
{
zoom
}
rotation
=
{
rotation
}
aspect
=
{
aspectRatio
}
cropShape
=
"rect"
showGrid
=
{
false
}
onCropChange
=
{
setCrop
}
onZoomChange
=
{
setZoom
}
onRotationChange
=
{
setRotation
}
onCropComplete
=
{
onCropComplete
}
/>
)
}
</
Grid
>
<
Grid
item
xs
=
{
12
}
style
=
{
{
marginTop
:
'
20px
'
}
}
>
<
Stack
spacing
=
{
2
}
>
<
FormControl
fullWidth
>
<
ButtonGroup
variant
=
"outlined"
aria-label
=
"outlined button group"
>
{
aspectRatios
.
map
((
ratio
)
=>
(
<
Button
key
=
{
ratio
.
label
}
onClick
=
{
()
=>
handleAspectRatioChange
(
ratio
.
value
)
}
variant
=
{
aspectRatio
===
ratio
.
value
?
'
contained
'
:
'
outlined
'
}
>
{
ratio
.
label
}
</
Button
>
))
}
{
originalAspectRatio
&&
(
<
Button
onClick
=
{
()
=>
handleAspectRatioChange
(
originalAspectRatio
)
}
variant
=
{
aspectRatio
===
originalAspectRatio
?
'
contained
'
:
'
outlined
'
}
>
Original (
{
originalAspectRatio
.
toFixed
(
2
)
}
)
</
Button
>
)
}
</
ButtonGroup
>
</
FormControl
>
<
Stack
direction
=
"row"
alignItems
=
"center"
spacing
=
{
2
}
>
<
Button
variant
=
"outlined"
color
=
"success"
onClick
=
{
()
=>
handleZoomChange
(
zoom
-
0.1
)
}
disabled
=
{
zoom
<=
1
}
><
ZoomOutIcon
/></
Button
>
<
Slider
value
=
{
zoom
}
min
=
{
1
}
max
=
{
3
}
step
=
{
0.1
}
onChange
=
{
(
e
,
value
)
=>
handleZoomChange
(
value
as
number
)
}
/>
<
Button
variant
=
"outlined"
color
=
"success"
onClick
=
{
()
=>
handleZoomChange
(
zoom
+
0.1
)
}
disabled
=
{
zoom
>=
3
}
><
ZoomInIcon
/></
Button
>
</
Stack
>
<
Stack
direction
=
"row"
alignItems
=
"center"
spacing
=
{
2
}
>
<
Button
variant
=
"outlined"
color
=
"success"
onClick
=
{
()
=>
handleRotationChange
(
rotation
-
10
)
}
disabled
=
{
rotation
<=
0
}
><
RotateLeftIcon
/></
Button
>
<
Slider
value
=
{
rotation
}
min
=
{
0
}
max
=
{
360
}
step
=
{
1
}
onChange
=
{
(
e
,
value
)
=>
handleRotationChange
(
value
as
number
)
}
/>
<
Button
variant
=
"outlined"
color
=
"success"
onClick
=
{
()
=>
handleRotationChange
(
rotation
+
10
)
}
disabled
=
{
rotation
>=
360
}
><
RotateRightIcon
/></
Button
>
</
Stack
>
<
input
accept
=
"image/*"
type
=
"file"
onChange
=
{
handleFileChange
}
style
=
{
{
display
:
'
none
'
}
}
id
=
"file-upload"
/>
<
label
htmlFor
=
"file-upload"
>
<
Button
variant
=
"outlined"
component
=
"span"
>
Upload New Image
</
Button
>
</
label
>
</
Stack
>
</
Grid
>
<
Grid
item
xs
=
{
12
}
style
=
{
{
marginTop
:
'
20px
'
}
}
>
<
Grid
container
justifyContent
=
"center"
>
<
Button
variant
=
"outlined"
onClick
=
{
onClose
}
style
=
{
{
marginRight
:
'
10px
'
}
}
>
Cancel
</
Button
>
<
Button
variant
=
"contained"
onClick
=
{
handleSave
}
>
Save
</
Button
>
</
Grid
>
</
Grid
>
</
Grid
>
</
Modal
>
);
};
export
default
EditImageModal
;
This diff is collapsed.
Click to expand it.
src/shared/sections/media/view/crop-image/cropImage.ts
0 → 100644
+
68
−
0
Voir le fichier @
4e679ebe
import
{
Area
}
from
'
react-easy-crop
'
;
export
const
getCroppedImg
=
(
imageSrc
:
string
,
pixelCrop
:
Area
,
rotation
=
0
):
Promise
<
Blob
|
null
>
=>
{
const
createImage
=
(
url
:
string
):
Promise
<
HTMLImageElement
>
=>
new
Promise
((
resolve
,
reject
)
=>
{
const
image
=
new
Image
();
image
.
setAttribute
(
'
crossOrigin
'
,
'
anonymous
'
);
image
.
onload
=
()
=>
resolve
(
image
);
image
.
onerror
=
(
error
)
=>
reject
(
error
);
image
.
src
=
url
;
});
const
getRadianAngle
=
(
degreeValue
:
number
)
=>
(
degreeValue
*
Math
.
PI
)
/
180
;
const
rotateSize
=
(
width
:
number
,
height
:
number
,
rotation
:
number
)
=>
{
const
rotRad
=
getRadianAngle
(
rotation
);
return
{
width
:
Math
.
abs
(
Math
.
cos
(
rotRad
)
*
width
)
+
Math
.
abs
(
Math
.
sin
(
rotRad
)
*
height
),
height
:
Math
.
abs
(
Math
.
cos
(
rotRad
)
*
height
)
+
Math
.
abs
(
Math
.
sin
(
rotRad
)
*
width
),
};
};
return
createImage
(
imageSrc
).
then
((
image
)
=>
{
const
canvas
=
document
.
createElement
(
'
canvas
'
);
const
ctx
=
canvas
.
getContext
(
'
2d
'
);
if
(
!
ctx
)
{
return
null
;
}
const
{
width
:
bBoxWidth
,
height
:
bBoxHeight
}
=
rotateSize
(
image
.
width
,
image
.
height
,
rotation
);
canvas
.
width
=
bBoxWidth
;
canvas
.
height
=
bBoxHeight
;
ctx
.
translate
(
bBoxWidth
/
2
,
bBoxHeight
/
2
);
ctx
.
rotate
(
getRadianAngle
(
rotation
));
ctx
.
drawImage
(
image
,
-
image
.
width
/
2
,
-
image
.
height
/
2
);
const
data
=
ctx
.
getImageData
(
0
,
0
,
bBoxWidth
,
bBoxHeight
);
canvas
.
width
=
pixelCrop
.
width
;
canvas
.
height
=
pixelCrop
.
height
;
ctx
.
putImageData
(
data
,
-
pixelCrop
.
x
,
-
pixelCrop
.
y
);
return
new
Promise
<
Blob
|
null
>
((
resolve
)
=>
{
canvas
.
toBlob
((
blob
)
=>
{
resolve
(
blob
);
},
'
image/png
'
);
});
});
};
This diff is collapsed.
Click to expand it.
Aperçu
0%
Veuillez réessayer
ou
joindre un nouveau fichier
.
Annuler
You are about to add
0
people
to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Enregistrer le commentaire
Annuler
Veuillez vous
inscrire
ou vous
se connecter
pour commenter