@h4md1/visual-image-tool 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -37
- package/dist/visual-image-tool.esm.js +921 -836
- package/dist/visual-image-tool.esm.js.map +1 -1
- package/dist/visual-image-tool.js +921 -836
- package/dist/visual-image-tool.js.map +1 -1
- package/dist/visual-image-tool.umd.js +1 -1
- package/dist/visual-image-tool.umd.js.map +1 -1
- package/package.json +48 -42
- package/src/index.js +1 -1
- package/src/visual-image-tool.js +924 -840
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-image-tool.js","sources":["../src/visual-image-tool.js","../src/index.js"],"sourcesContent":["/**\n * ImageTool - Un outil léger pour définir des points focaux et zones de recadrage sur des images\n * @module visual-image-tool\n */\n\nclass VisualImageTool {\n /**\n * Crée une instance de l'outil d'image\n * @param {Object} options - Options de configuration\n * @param {HTMLElement|string} options.imageElement - Élément image ou sélecteur CSS\n * @param {Object} [options.focusPoint] - Configuration du point focal\n * @param {boolean} [options.focusPoint.enabled=true] - Activer la fonctionnalité de point focal\n * @param {Object} [options.focusPoint.style] - Styles personnalisés pour le marqueur de point focal\n * @param {Object} [options.cropZone] - Configuration de la zone de recadrage\n * @param {boolean} [options.cropZone.enabled=true] - Activer la fonctionnalité de zone de recadrage\n * @param {Object} [options.cropZone.style] - Styles personnalisés pour l'overlay de recadrage\n * @param {Function} [options.onChange] - Callback appelé lors des changements\n */\n constructor(options) {\n // Valider les options\n if (!options || !options.imageElement) {\n throw new Error('L\\'élément image est requis');\n }\n \n // Initialiser les propriétés\n this.imageElement = typeof options.imageElement === 'string' \n ? document.querySelector(options.imageElement) \n : options.imageElement;\n \n if (!this.imageElement || this.imageElement.tagName !== 'IMG') {\n throw new Error('Élément image invalide');\n }\n \n // Options par défaut\n this.options = {\n focusPoint: {\n enabled: true,\n style: {\n width: '30px',\n height: '30px',\n border: '3px solid white',\n boxShadow: '0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)',\n backgroundColor: 'rgba(255, 0, 0, 0.5)'\n },\n ...options.focusPoint\n },\n cropZone: {\n enabled: true,\n style: {\n border: '1px dashed #fff',\n backgroundColor: 'rgba(0, 0, 0, 0.4)'\n },\n handleStyle: {\n width: '14px',\n height: '14px',\n backgroundColor: 'white',\n border: '2px solid black',\n boxShadow: '0 0 3px rgba(0,0,0,0.5)'\n },\n ...options.cropZone\n },\n onChange: options.onChange || (() => {}),\n debug: options.debug || false\n };\n \n // État interne\n this.state = {\n focusMarker: null,\n cropOverlay: null,\n focusActive: false,\n cropActive: false,\n focusPoint: { x: 0, y: 0 },\n cropZone: { x: 0, y: 0, width: 0, height: 0 },\n originalWidth: 1,\n originalHeight: 1,\n displayWidth: 1,\n displayHeight: 1,\n scaleX: 1,\n scaleY: 1\n };\n \n // Variables pour le suivi des interactions\n this.interaction = {\n focusDragging: false,\n focusDragOffsetX: 0,\n focusDragOffsetY: 0,\n cropDragging: false,\n cropResizing: false,\n activeHandle: null,\n startX: 0,\n startY: 0,\n startWidth: 0,\n startHeight: 0,\n startMouseX: 0,\n startMouseY: 0\n };\n \n // Initialiser l'outil\n this._init();\n }\n \n /**\n * Initialise l'outil d'image\n * @private\n */\n _init() {\n // Préparer le conteneur parent\n this._prepareContainer();\n \n // Initialiser les dimensions\n this._updateScaling();\n \n // Créer les éléments d'interface si activés\n if (this.options.focusPoint.enabled) {\n this._createFocusMarker();\n }\n \n if (this.options.cropZone.enabled) {\n this._createCropOverlay();\n }\n \n // Ajouter les écouteurs d'événements\n this._setupEventListeners();\n }\n \n /**\n * Prépare le conteneur parent de l'image\n * @private\n */\n _prepareContainer() {\n // S'assurer que le parent est positionné\n if (this.imageElement.parentNode) {\n this.imageElement.parentNode.style.position = 'relative';\n }\n }\n \n /**\n * Met à jour les facteurs d'échelle\n * @private\n */\n _updateScaling() {\n this.state.originalWidth = this.imageElement.naturalWidth || 1;\n this.state.originalHeight = this.imageElement.naturalHeight || 1;\n this.state.displayWidth = this.imageElement.offsetWidth;\n this.state.displayHeight = this.imageElement.offsetHeight;\n this.state.scaleX = this.state.displayWidth / this.state.originalWidth;\n this.state.scaleY = this.state.displayHeight / this.state.originalHeight;\n \n // Repositionner les éléments si actifs\n if (this.state.focusActive) {\n this._updateFocusMarkerPosition();\n }\n \n if (this.state.cropActive) {\n this._updateCropOverlayPosition();\n }\n }\n \n /**\n * Convertit des coordonnées d'affichage en coordonnées originales\n * @private\n * @param {number} scaledX - Coordonnée X à l'échelle d'affichage\n * @param {number} scaledY - Coordonnée Y à l'échelle d'affichage\n * @returns {Object} Coordonnées originales\n */\n _toOriginalCoords(scaledX, scaledY) {\n return { \n x: scaledX / this.state.scaleX, \n y: scaledY / this.state.scaleY \n };\n }\n \n /**\n * Convertit des coordonnées originales en coordonnées d'affichage\n * @private\n * @param {number} originalX - Coordonnée X originale\n * @param {number} originalY - Coordonnée Y originale\n * @returns {Object} Coordonnées à l'échelle d'affichage\n */\n _toScaledCoords(originalX, originalY) {\n return { \n x: originalX * this.state.scaleX, \n y: originalY * this.state.scaleY \n };\n }\n \n /**\n * Crée le marqueur de point focal\n * @private\n */\n _createFocusMarker() {\n if (this.state.focusMarker) return;\n \n const marker = document.createElement('div');\n marker.style.position = 'absolute';\n marker.style.width = this.options.focusPoint.style.width;\n marker.style.height = this.options.focusPoint.style.height;\n marker.style.border = this.options.focusPoint.style.border;\n marker.style.boxShadow = this.options.focusPoint.style.boxShadow;\n marker.style.backgroundColor = this.options.focusPoint.style.backgroundColor;\n marker.style.cursor = 'move';\n marker.style.display = 'none';\n marker.style.zIndex = '999';\n marker.style.clipPath = 'polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)';\n \n this.imageElement.parentNode.appendChild(marker);\n this.state.focusMarker = marker;\n \n // Ajouter les écouteurs d'événements au marqueur\n marker.addEventListener('mousedown', this._handleFocusMarkerMouseDown.bind(this));\n }\n \n /**\n * Gère l'événement mousedown sur le marqueur de point focal\n * @private\n * @param {MouseEvent} e - Événement mousedown\n */\n _handleFocusMarkerMouseDown(e) {\n this.interaction.focusDragging = true;\n this.state.focusMarker.style.cursor = 'grabbing';\n \n // Calculer le décalage par rapport au centre du marqueur\n const rect = this.state.focusMarker.getBoundingClientRect();\n this.interaction.focusDragOffsetX = e.clientX - (rect.left + rect.width / 2);\n this.interaction.focusDragOffsetY = e.clientY - (rect.top + rect.height / 2);\n \n e.preventDefault();\n }\n \n /**\n * Crée l'overlay de zone de recadrage\n * @private\n */\n _createCropOverlay() {\n if (this.state.cropOverlay) return;\n \n const overlay = document.createElement('div');\n overlay.style.position = 'absolute';\n overlay.style.border = this.options.cropZone.style.border;\n overlay.style.backgroundColor = this.options.cropZone.style.backgroundColor;\n overlay.style.boxSizing = 'border-box';\n overlay.style.cursor = 'move';\n overlay.style.display = 'none';\n overlay.style.zIndex = '998';\n \n // Ajouter les poignées de redimensionnement\n const handles = ['tl', 'tm', 'tr', 'ml', 'mr', 'bl', 'bm', 'br'];\n handles.forEach(handleType => {\n const handle = document.createElement('div');\n handle.style.position = 'absolute';\n handle.style.width = this.options.cropZone.handleStyle.width;\n handle.style.height = this.options.cropZone.handleStyle.height;\n handle.style.backgroundColor = this.options.cropZone.handleStyle.backgroundColor;\n handle.style.border = this.options.cropZone.handleStyle.border;\n handle.style.boxShadow = this.options.cropZone.handleStyle.boxShadow;\n handle.style.boxSizing = 'border-box';\n handle.dataset.handle = handleType;\n \n // Positionner la poignée\n switch (handleType) {\n case 'tl': // Top-left\n handle.style.top = '-7px';\n handle.style.left = '-7px';\n handle.style.cursor = 'nwse-resize';\n break;\n case 'tm': // Top-middle\n handle.style.top = '-7px';\n handle.style.left = '50%';\n handle.style.marginLeft = '-7px';\n handle.style.cursor = 'ns-resize';\n break;\n case 'tr': // Top-right\n handle.style.top = '-7px';\n handle.style.right = '-7px';\n handle.style.cursor = 'nesw-resize';\n break;\n case 'ml': // Middle-left\n handle.style.top = '50%';\n handle.style.left = '-7px';\n handle.style.marginTop = '-7px';\n handle.style.cursor = 'ew-resize';\n break;\n case 'mr': // Middle-right\n handle.style.top = '50%';\n handle.style.right = '-7px';\n handle.style.marginTop = '-7px';\n handle.style.cursor = 'ew-resize';\n break;\n case 'bl': // Bottom-left\n handle.style.bottom = '-7px';\n handle.style.left = '-7px';\n handle.style.cursor = 'nesw-resize';\n break;\n case 'bm': // Bottom-middle\n handle.style.bottom = '-7px';\n handle.style.left = '50%';\n handle.style.marginLeft = '-7px';\n handle.style.cursor = 'ns-resize';\n break;\n case 'br': // Bottom-right\n handle.style.bottom = '-7px';\n handle.style.right = '-7px';\n handle.style.cursor = 'nwse-resize';\n break;\n }\n \n // Ajouter l'écouteur d'événement\n handle.addEventListener('mousedown', (e) => this._handleCropHandleMouseDown(e, handleType));\n \n overlay.appendChild(handle);\n });\n \n // Ajouter l'écouteur pour le déplacement de l'overlay\n overlay.addEventListener('mousedown', this._handleCropOverlayMouseDown.bind(this));\n \n this.imageElement.parentNode.appendChild(overlay);\n this.state.cropOverlay = overlay;\n }\n \n /**\n * Gère l'événement mousedown sur une poignée de redimensionnement\n * @private\n * @param {MouseEvent} e - Événement mousedown\n * @param {string} handleType - Type de poignée\n */\n _handleCropHandleMouseDown(e, handleType) {\n this.interaction.cropResizing = true;\n this.interaction.activeHandle = handleType;\n \n // Enregistrer les dimensions et position initiales\n this.interaction.startX = parseInt(this.state.cropOverlay.style.left, 10) || 0;\n this.interaction.startY = parseInt(this.state.cropOverlay.style.top, 10) || 0;\n this.interaction.startWidth = this.state.cropOverlay.offsetWidth;\n this.interaction.startHeight = this.state.cropOverlay.offsetHeight;\n this.interaction.startMouseX = e.clientX;\n this.interaction.startMouseY = e.clientY;\n \n e.preventDefault();\n e.stopPropagation();\n }\n \n /**\n * Gère l'événement mousedown sur l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousedown\n */\n _handleCropOverlayMouseDown(e) {\n // Ignorer si on clique sur une poignée\n if (e.target !== this.state.cropOverlay) return;\n \n this.interaction.cropDragging = true;\n this.state.cropOverlay.style.cursor = 'grabbing';\n \n // Enregistrer la position initiale\n this.interaction.startX = parseInt(this.state.cropOverlay.style.left, 10) || 0;\n this.interaction.startY = parseInt(this.state.cropOverlay.style.top, 10) || 0;\n this.interaction.startMouseX = e.clientX;\n this.interaction.startMouseY = e.clientY;\n \n e.preventDefault();\n }\n \n /**\n * Configure les écouteurs d'événements globaux\n * @private\n */\n _setupEventListeners() {\n // Écouteur pour le redimensionnement de la fenêtre\n window.addEventListener('resize', this._updateScaling.bind(this));\n \n // Écouteur pour le chargement de l'image\n if (!this.imageElement.complete) {\n this.imageElement.addEventListener('load', this._updateScaling.bind(this));\n }\n \n // Écouteurs pour les interactions de souris\n document.addEventListener('mouseup', this._handleMouseUp.bind(this));\n document.addEventListener('mousemove', this._handleMouseMove.bind(this));\n }\n \n /**\n * Gère l'événement mouseup global\n * @private\n */\n _handleMouseUp() {\n if (this.interaction.focusDragging) {\n this.interaction.focusDragging = false;\n if (this.state.focusMarker) this.state.focusMarker.style.cursor = 'move';\n }\n \n if (this.interaction.cropDragging) {\n this.interaction.cropDragging = false;\n if (this.state.cropOverlay) this.state.cropOverlay.style.cursor = 'move';\n }\n \n this.interaction.cropResizing = false;\n this.interaction.activeHandle = null;\n document.body.style.cursor = 'default';\n }\n \n /**\n * Gère l'événement mousemove global\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleMouseMove(e) {\n // Gestion du déplacement du point focal\n if (this.interaction.focusDragging && this.state.focusMarker) {\n this._handleFocusMarkerDrag(e);\n }\n \n // Gestion du déplacement de la zone de recadrage\n if (this.interaction.cropDragging) {\n this._handleCropOverlayDrag(e);\n }\n \n // Gestion du redimensionnement de la zone de recadrage\n if (this.interaction.cropResizing) {\n this._handleCropOverlayResize(e);\n }\n }\n \n /**\n * Gère le déplacement du marqueur de point focal\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleFocusMarkerDrag(e) {\n const imageRect = this.imageElement.getBoundingClientRect();\n \n // Calculer la position cible relative à l'image\n const targetScaledX = e.clientX - imageRect.left - this.interaction.focusDragOffsetX;\n const targetScaledY = e.clientY - imageRect.top - this.interaction.focusDragOffsetY;\n \n // Convertir en coordonnées originales\n const original = this._toOriginalCoords(targetScaledX, targetScaledY);\n \n // Mettre à jour le point focal\n this.setFocusPoint(original.x, original.y);\n }\n \n /**\n * Gère le déplacement de l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleCropOverlayDrag(e) {\n const deltaX = e.clientX - this.interaction.startMouseX;\n const deltaY = e.clientY - this.interaction.startMouseY;\n \n // Calculer la nouvelle position en pixels d'affichage\n let newX = this.interaction.startX + deltaX;\n let newY = this.interaction.startY + deltaY;\n \n // Convertir en coordonnées originales\n const original = this._toOriginalCoords(newX, newY);\n \n // Obtenir les dimensions actuelles en coordonnées originales\n const { width, height } = this.state.cropZone;\n \n // Mettre à jour la zone de recadrage\n this.setCropZone(original.x, original.y, width, height);\n }\n \n /**\n * Gère le redimensionnement de l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleCropOverlayResize(e) {\n if (!this.interaction.activeHandle) return;\n \n const deltaX = e.clientX - this.interaction.startMouseX;\n const deltaY = e.clientY - this.interaction.startMouseY;\n \n let newX = this.interaction.startX;\n let newY = this.interaction.startY;\n let newWidth = this.interaction.startWidth;\n let newHeight = this.interaction.startHeight;\n \n // Ajuster en fonction de la poignée active\n if (this.interaction.activeHandle.includes('t')) { // Top\n newY = this.interaction.startY + deltaY;\n newHeight = this.interaction.startHeight - deltaY;\n }\n if (this.interaction.activeHandle.includes('b')) { // Bottom\n newHeight = this.interaction.startHeight + deltaY;\n }\n if (this.interaction.activeHandle.includes('l')) { // Left\n newX = this.interaction.startX + deltaX;\n newWidth = this.interaction.startWidth - deltaX;\n }\n if (this.interaction.activeHandle.includes('r')) { // Right\n newWidth = this.interaction.startWidth + deltaX;\n }\n \n // Empêcher les dimensions négatives\n if (newWidth < 10) {\n if (this.interaction.activeHandle.includes('l')) {\n newX = this.interaction.startX + this.interaction.startWidth - 10;\n }\n newWidth = 10;\n }\n if (newHeight < 10) {\n if (this.interaction.activeHandle.includes('t')) {\n newY = this.interaction.startY + this.interaction.startHeight - 10;\n }\n newHeight = 10;\n }\n \n // Convertir les coordonnées d'affichage en coordonnées originales\n const originalX = newX / this.state.scaleX;\n const originalY = newY / this.state.scaleY;\n const originalWidth = newWidth / this.state.scaleX;\n const originalHeight = newHeight / this.state.scaleY;\n \n // Mettre à jour la zone de recadrage\n this.setCropZone(originalX, originalY, originalWidth, originalHeight);\n }\n \n /**\n * Met à jour la position du marqueur de point focal\n * @private\n */\n _updateFocusMarkerPosition() {\n if (!this.state.focusMarker) return;\n \n const { x, y } = this.state.focusPoint;\n \n // Limiter les coordonnées aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n \n // Mettre à jour l'état si les coordonnées ont été limitées\n if (x !== clampedX || y !== clampedY) {\n this.state.focusPoint = { x: clampedX, y: clampedY };\n }\n \n const scaled = this._toScaledCoords(clampedX, clampedY);\n\n // LOGGING: Validate padding offset\n if (this.options.debug) {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n const paddingTop = parseFloat(computedStyle.paddingTop);\n console.log('[FocusMarker] scaled:', scaled, 'paddingLeft:', paddingLeft, 'paddingTop:', paddingTop, 'containerRect:', container.getBoundingClientRect());\n }\n\n // Ajuster pour centrer le marqueur\n // Adjust for container padding (use unique variable names)\n let focusPaddingLeft = 0, focusPaddingTop = 0;\n {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n focusPaddingLeft = parseFloat(computedStyle.paddingLeft);\n focusPaddingTop = parseFloat(computedStyle.paddingTop);\n }\n\n this.state.focusMarker.style.left = (scaled.x + focusPaddingLeft - this.state.focusMarker.offsetWidth / 2) + 'px';\n this.state.focusMarker.style.top = (scaled.y + focusPaddingTop - this.state.focusMarker.offsetHeight / 2) + 'px';\n if (this.options.debug) {\n console.log('[FocusMarker] style.left:', this.state.focusMarker.style.left, 'style.top:', this.state.focusMarker.style.top);\n }\n }\n \n /**\n * Met à jour la position et les dimensions de l'overlay de recadrage\n * @private\n */\n _updateCropOverlayPosition() {\n if (!this.state.cropOverlay) return;\n \n const { x, y, width, height } = this.state.cropZone;\n \n // Limiter aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight - height));\n const clampedWidth = Math.max(10, Math.min(width, this.state.originalWidth - clampedX));\n const clampedHeight = Math.max(10, Math.min(height, this.state.originalHeight - clampedY));\n \n // Mettre à jour l'état si les valeurs ont été limitées\n if (x !== clampedX || y !== clampedY || width !== clampedWidth || height !== clampedHeight) {\n this.state.cropZone = { x: clampedX, y: clampedY, width: clampedWidth, height: clampedHeight };\n }\n \n // Convertir en coordonnées d'affichage\n const scaled = this._toScaledCoords(clampedX, clampedY);\n const scaledWidth = clampedWidth * this.state.scaleX;\n const scaledHeight = clampedHeight * this.state.scaleY;\n\n // LOGGING: Validate padding offset\n if (this.options.debug) {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n const paddingTop = parseFloat(computedStyle.paddingTop);\n console.log('[CropOverlay] scaled:', scaled, 'paddingLeft:', paddingLeft, 'paddingTop:', paddingTop, 'containerRect:', container.getBoundingClientRect());\n }\n\n // Mettre à jour l'overlay\n // Adjust for container padding (use unique variable names)\n let cropPaddingLeft = 0, cropPaddingTop = 0;\n {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n cropPaddingLeft = parseFloat(computedStyle.paddingLeft);\n cropPaddingTop = parseFloat(computedStyle.paddingTop);\n }\n\n this.state.cropOverlay.style.left = (scaled.x + cropPaddingLeft) + 'px';\n this.state.cropOverlay.style.top = (scaled.y + cropPaddingTop) + 'px';\n this.state.cropOverlay.style.width = scaledWidth + 'px';\n this.state.cropOverlay.style.height = scaledHeight + 'px';\n if (this.options.debug) {\n console.log('[CropOverlay] style.left:', this.state.cropOverlay.style.left, 'style.top:', this.state.cropOverlay.style.top);\n }\n }\n \n /**\n * Active ou désactive le point focal\n * @public\n * @param {boolean} active - État d'activation\n * @returns {ImageTool} Instance pour chaînage\n */\n toggleFocusPoint(active) {\n if (!this.options.focusPoint.enabled) return this;\n \n if (active === undefined) {\n active = !this.state.focusActive;\n }\n \n if (active && !this.state.focusActive) {\n // Activer le point focal\n if (!this.state.focusMarker) {\n this._createFocusMarker();\n }\n \n // Positionner au centre de l'image par défaut si pas déjà défini\n if (this.state.focusPoint.x === 0 && this.state.focusPoint.y === 0) {\n this.state.focusPoint = {\n x: this.state.originalWidth / 2,\n y: this.state.originalHeight / 2\n };\n }\n \n this._updateFocusMarkerPosition();\n this.state.focusMarker.style.display = 'block';\n this.state.focusActive = true;\n } else if (!active && this.state.focusActive) {\n // Désactiver le point focal\n if (this.state.focusMarker) {\n this.state.focusMarker.style.display = 'none';\n }\n this.state.focusActive = false;\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Active ou désactive la zone de recadrage\n * @public\n * @param {boolean} active - État d'activation\n * @returns {ImageTool} Instance pour chaînage\n */\n toggleCropZone(active) {\n if (!this.options.cropZone.enabled) return this;\n \n if (active === undefined) {\n active = !this.state.cropActive;\n }\n \n if (active && !this.state.cropActive) {\n // Activer la zone de recadrage\n if (!this.state.cropOverlay) {\n this._createCropOverlay();\n }\n \n // Définir une zone par défaut si pas déjà définie\n if (this.state.cropZone.width === 0 || this.state.cropZone.height === 0) {\n const defaultWidth = this.state.originalWidth / 2;\n const defaultHeight = this.state.originalHeight / 2;\n const defaultX = (this.state.originalWidth - defaultWidth) / 2;\n const defaultY = (this.state.originalHeight - defaultHeight) / 2;\n \n this.state.cropZone = {\n x: defaultX,\n y: defaultY,\n width: defaultWidth,\n height: defaultHeight\n };\n }\n \n this._updateCropOverlayPosition();\n this.state.cropOverlay.style.display = 'block';\n this.state.cropActive = true;\n } else if (!active && this.state.cropActive) {\n // Désactiver la zone de recadrage\n if (this.state.cropOverlay) {\n this.state.cropOverlay.style.display = 'none';\n }\n this.state.cropActive = false;\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Définit la position du point focal\n * @public\n * @param {number} x - Coordonnée X en pixels originaux\n * @param {number} y - Coordonnée Y en pixels originaux\n * @returns {ImageTool} Instance pour chaînage\n */\n setFocusPoint(x, y) {\n // Limiter les coordonnées aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n \n this.state.focusPoint = { x: clampedX, y: clampedY };\n \n if (this.state.focusActive && this.state.focusMarker) {\n this._updateFocusMarkerPosition();\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Définit la position et les dimensions de la zone de recadrage\n * @public\n * @param {number} x - Coordonnée X en pixels originaux\n * @param {number} y - Coordonnée Y en pixels originaux\n * @param {number} width - Largeur en pixels originaux\n * @param {number} height - Hauteur en pixels originaux\n * @returns {ImageTool} Instance pour chaînage\n */\n setCropZone(x, y, width, height) {\n // Limiter aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight - height));\n const clampedWidth = Math.max(10, Math.min(width, this.state.originalWidth - clampedX));\n const clampedHeight = Math.max(10, Math.min(height, this.state.originalHeight - clampedY));\n \n this.state.cropZone = {\n x: clampedX,\n y: clampedY,\n width: clampedWidth,\n height: clampedHeight\n };\n \n if (this.state.cropActive && this.state.cropOverlay) {\n this._updateCropOverlayPosition();\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Obtient la position actuelle du point focal\n * @public\n * @returns {Object} Coordonnées du point focal {x, y}\n */\n getFocusPoint() {\n return { ...this.state.focusPoint };\n }\n \n /**\n * Obtient la position et les dimensions actuelles de la zone de recadrage\n * @public\n * @returns {Object} Zone de recadrage {x, y, width, height}\n */\n getCropZone() {\n return { ...this.state.cropZone };\n }\n \n /**\n * Obtient les dimensions originales de l'image\n * @public\n * @returns {Object} Dimensions {width, height}\n */\n getImageDimensions() {\n return {\n width: this.state.originalWidth,\n height: this.state.originalHeight\n };\n }\n \n /**\n * Notifie les changements via le callback\n * @private\n */\n _notifyChange() {\n if (typeof this.options.onChange === 'function') {\n this.options.onChange({\n focusPoint: this.getFocusPoint(),\n cropZone: this.getCropZone(),\n focusActive: this.state.focusActive,\n cropActive: this.state.cropActive\n });\n }\n }\n \n /**\n * Détruit l'instance et nettoie les ressources\n * @public\n */\n destroy() {\n // Supprimer les éléments DOM\n if (this.state.focusMarker && this.state.focusMarker.parentNode) {\n this.state.focusMarker.parentNode.removeChild(this.state.focusMarker);\n }\n \n if (this.state.cropOverlay && this.state.cropOverlay.parentNode) {\n this.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay);\n }\n \n // Supprimer les écouteurs d'événements\n window.removeEventListener('resize', this._updateScaling.bind(this));\n document.removeEventListener('mouseup', this._handleMouseUp.bind(this));\n document.removeEventListener('mousemove', this._handleMouseMove.bind(this));\n \n // Réinitialiser l'état\n this.state = null;\n this.interaction = null;\n this.options = null;\n this.imageElement = null;\n }\n }\n \n // Exporter la classe\n export default VisualImageTool;\n ","/**\n * Point d'entrée principal pour le package image-tool\n * Exporte la classe VisualImageTool\n */\n\nimport VisualImageTool from './visual-image-tool.js';\n\n// Exporter la classe comme export par défaut\nexport default VisualImageTool;\n\n// Exporter également comme export nommé pour plus de flexibilité\nexport { VisualImageTool };\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"visual-image-tool.js","sources":["../src/visual-image-tool.js","../src/index.js"],"sourcesContent":["/**\n * ImageTool - Un outil léger pour définir des points focaux et zones de recadrage sur des images\n * @module visual-image-tool\n */\n\nclass VisualImageTool {\n\t/**\n\t * Crée une instance de l'outil d'image\n\t * @param {Object} options - Options de configuration\n\t * @param {HTMLElement|string} options.imageElement - Élément image ou sélecteur CSS\n\t * @param {Object} [options.focusPoint] - Configuration du point focal\n\t * @param {boolean} [options.focusPoint.enabled=true] - Activer la fonctionnalité de point focal\n\t * @param {Object} [options.focusPoint.style] - Styles personnalisés pour le marqueur de point focal\n\t * @param {Object} [options.cropZone] - Configuration de la zone de recadrage\n\t * @param {boolean} [options.cropZone.enabled=true] - Activer la fonctionnalité de zone de recadrage\n\t * @param {Object} [options.cropZone.style] - Styles personnalisés pour l'overlay de recadrage\n\t * @param {Function} [options.onChange] - Callback appelé lors des changements\n\t */\n\tconstructor(options) {\n\t\t// Valider les options\n\t\tif (!options || !options.imageElement) {\n\t\t\tthrow new Error(\"L'élément image est requis\");\n\t\t}\n\n\t\t// Initialiser les propriétés\n\t\tthis.imageElement =\n\t\t\ttypeof options.imageElement === \"string\"\n\t\t\t\t? document.querySelector(options.imageElement)\n\t\t\t\t: options.imageElement;\n\n\t\tif (!this.imageElement || this.imageElement.tagName !== \"IMG\") {\n\t\t\tthrow new Error(\"Élément image invalide\");\n\t\t}\n\n\t\t// Options par défaut\n\t\tthis.options = {\n\t\t\tfocusPoint: {\n\t\t\t\tenabled: true,\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: \"30px\",\n\t\t\t\t\theight: \"30px\",\n\t\t\t\t\tborder: \"3px solid white\",\n\t\t\t\t\tboxShadow: \"0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)\",\n\t\t\t\t\tbackgroundColor: \"rgba(255, 0, 0, 0.5)\",\n\t\t\t\t},\n\t\t\t\t...options.focusPoint,\n\t\t\t},\n\t\t\tcropZone: {\n\t\t\t\tenabled: true,\n\t\t\t\tstyle: {\n\t\t\t\t\tborder: \"1px dashed #fff\",\n\t\t\t\t\tbackgroundColor: \"rgba(0, 0, 0, 0.4)\",\n\t\t\t\t},\n\t\t\t\thandleStyle: {\n\t\t\t\t\twidth: \"14px\",\n\t\t\t\t\theight: \"14px\",\n\t\t\t\t\tbackgroundColor: \"white\",\n\t\t\t\t\tborder: \"2px solid black\",\n\t\t\t\t\tboxShadow: \"0 0 3px rgba(0,0,0,0.5)\",\n\t\t\t\t},\n\t\t\t\t...options.cropZone,\n\t\t\t},\n\t\t\tonChange: options.onChange || (() => {}),\n\t\t\tdebug: options.debug || false,\n\t\t};\n\n\t\t// État interne\n\t\tthis.state = {\n\t\t\tfocusMarker: null,\n\t\t\tcropOverlay: null,\n\t\t\tfocusActive: false,\n\t\t\tcropActive: false,\n\t\t\tfocusPoint: { x: 0, y: 0 },\n\t\t\tcropZone: { x: 0, y: 0, width: 0, height: 0 },\n\t\t\toriginalWidth: 1,\n\t\t\toriginalHeight: 1,\n\t\t\tdisplayWidth: 1,\n\t\t\tdisplayHeight: 1,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t};\n\n\t\t// Variables pour le suivi des interactions\n\t\tthis.interaction = {\n\t\t\tfocusDragging: false,\n\t\t\tfocusDragOffsetX: 0,\n\t\t\tfocusDragOffsetY: 0,\n\t\t\tcropDragging: false,\n\t\t\tcropResizing: false,\n\t\t\tactiveHandle: null,\n\t\t\tstartX: 0,\n\t\t\tstartY: 0,\n\t\t\tstartWidth: 0,\n\t\t\tstartHeight: 0,\n\t\t\tstartMouseX: 0,\n\t\t\tstartMouseY: 0,\n\t\t};\n\n\t\t// Initialiser l'outil\n\t\tthis._init();\n\t}\n\n\t/**\n\t * Initialise l'outil d'image\n\t * @private\n\t */\n\t_init() {\n\t\t// Préparer le conteneur parent\n\t\tthis._prepareContainer();\n\n\t\t// Initialiser les dimensions\n\t\tthis._updateScaling();\n\n\t\t// Créer les éléments d'interface si activés\n\t\tif (this.options.focusPoint.enabled) {\n\t\t\tthis._createFocusMarker();\n\t\t}\n\n\t\tif (this.options.cropZone.enabled) {\n\t\t\tthis._createCropOverlay();\n\t\t}\n\n\t\t// Ajouter les écouteurs d'événements\n\t\tthis._setupEventListeners();\n\t}\n\n\t/**\n\t * Prépare le conteneur parent de l'image\n\t * @private\n\t */\n\t_prepareContainer() {\n\t\t// S'assurer que le parent est positionné\n\t\tif (this.imageElement.parentNode) {\n\t\t\tthis.imageElement.parentNode.style.position = \"relative\";\n\t\t}\n\t}\n\n\t/**\n\t * Met à jour les facteurs d'échelle\n\t * @private\n\t */\n\t_updateScaling() {\n\t\tthis.state.originalWidth = this.imageElement.naturalWidth || 1;\n\t\tthis.state.originalHeight = this.imageElement.naturalHeight || 1;\n\t\tthis.state.displayWidth = this.imageElement.offsetWidth;\n\t\tthis.state.displayHeight = this.imageElement.offsetHeight;\n\t\tthis.state.scaleX = this.state.displayWidth / this.state.originalWidth;\n\t\tthis.state.scaleY = this.state.displayHeight / this.state.originalHeight;\n\n\t\t// Repositionner les éléments si actifs\n\t\tif (this.state.focusActive) {\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t}\n\n\t\tif (this.state.cropActive) {\n\t\t\tthis._updateCropOverlayPosition();\n\t\t}\n\t}\n\n\t/**\n\t * Convertit des coordonnées d'affichage en coordonnées originales\n\t * @private\n\t * @param {number} scaledX - Coordonnée X à l'échelle d'affichage\n\t * @param {number} scaledY - Coordonnée Y à l'échelle d'affichage\n\t * @returns {Object} Coordonnées originales\n\t */\n\t_toOriginalCoords(scaledX, scaledY) {\n\t\treturn {\n\t\t\tx: scaledX / this.state.scaleX,\n\t\t\ty: scaledY / this.state.scaleY,\n\t\t};\n\t}\n\n\t/**\n\t * Convertit des coordonnées originales en coordonnées d'affichage\n\t * @private\n\t * @param {number} originalX - Coordonnée X originale\n\t * @param {number} originalY - Coordonnée Y originale\n\t * @returns {Object} Coordonnées à l'échelle d'affichage\n\t */\n\t_toScaledCoords(originalX, originalY) {\n\t\treturn {\n\t\t\tx: originalX * this.state.scaleX,\n\t\t\ty: originalY * this.state.scaleY,\n\t\t};\n\t}\n\n\t/**\n\t * Crée le marqueur de point focal\n\t * @private\n\t */\n\t_createFocusMarker() {\n\t\tif (this.state.focusMarker) return;\n\n\t\tconst marker = document.createElement(\"div\");\n\t\tmarker.style.position = \"absolute\";\n\t\tmarker.style.width = this.options.focusPoint.style.width;\n\t\tmarker.style.height = this.options.focusPoint.style.height;\n\t\tmarker.style.border = this.options.focusPoint.style.border;\n\t\tmarker.style.boxShadow = this.options.focusPoint.style.boxShadow;\n\t\tmarker.style.backgroundColor =\n\t\t\tthis.options.focusPoint.style.backgroundColor;\n\t\tmarker.style.cursor = \"move\";\n\t\tmarker.style.display = \"none\";\n\t\tmarker.style.zIndex = \"999\";\n\t\tmarker.style.clipPath =\n\t\t\t\"polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)\";\n\n\t\tthis.imageElement.parentNode.appendChild(marker);\n\t\tthis.state.focusMarker = marker;\n\n\t\t// Ajouter les écouteurs d'événements au marqueur\n\t\tmarker.addEventListener(\n\t\t\t\"mousedown\",\n\t\t\tthis._handleFocusMarkerMouseDown.bind(this),\n\t\t);\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur le marqueur de point focal\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t */\n\t_handleFocusMarkerMouseDown(e) {\n\t\tthis.interaction.focusDragging = true;\n\t\tthis.state.focusMarker.style.cursor = \"grabbing\";\n\n\t\t// Calculer le décalage par rapport au centre du marqueur\n\t\tconst rect = this.state.focusMarker.getBoundingClientRect();\n\t\tthis.interaction.focusDragOffsetX =\n\t\t\te.clientX - (rect.left + rect.width / 2);\n\t\tthis.interaction.focusDragOffsetY =\n\t\t\te.clientY - (rect.top + rect.height / 2);\n\n\t\te.preventDefault();\n\t}\n\n\t/**\n\t * Crée l'overlay de zone de recadrage\n\t * @private\n\t */\n\t_createCropOverlay() {\n\t\tif (this.state.cropOverlay) return;\n\n\t\tconst overlay = document.createElement(\"div\");\n\t\toverlay.style.position = \"absolute\";\n\t\toverlay.style.border = this.options.cropZone.style.border;\n\t\toverlay.style.backgroundColor = this.options.cropZone.style.backgroundColor;\n\t\toverlay.style.boxSizing = \"border-box\";\n\t\toverlay.style.cursor = \"move\";\n\t\toverlay.style.display = \"none\";\n\t\toverlay.style.zIndex = \"998\";\n\n\t\t// Ajouter les poignées de redimensionnement\n\t\tconst handles = [\"tl\", \"tm\", \"tr\", \"ml\", \"mr\", \"bl\", \"bm\", \"br\"];\n\t\tfor (const handleType of handles) {\n\t\t\tconst handle = document.createElement(\"div\");\n\t\t\thandle.style.position = \"absolute\";\n\t\t\thandle.style.width = this.options.cropZone.handleStyle.width;\n\t\t\thandle.style.height = this.options.cropZone.handleStyle.height;\n\t\t\thandle.style.backgroundColor =\n\t\t\t\tthis.options.cropZone.handleStyle.backgroundColor;\n\t\t\thandle.style.border = this.options.cropZone.handleStyle.border;\n\t\t\thandle.style.boxShadow = this.options.cropZone.handleStyle.boxShadow;\n\t\t\thandle.style.boxSizing = \"border-box\";\n\t\t\thandle.dataset.handle = handleType;\n\n\t\t\t// Positionner la poignée\n\t\t\tswitch (handleType) {\n\t\t\t\tcase \"tl\": // Top-left\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nwse-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tm\": // Top-middle\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.left = \"50%\";\n\t\t\t\t\thandle.style.marginLeft = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ns-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tr\": // Top-right\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nesw-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ml\": // Middle-left\n\t\t\t\t\thandle.style.top = \"50%\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.marginTop = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ew-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"mr\": // Middle-right\n\t\t\t\t\thandle.style.top = \"50%\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.marginTop = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ew-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"bl\": // Bottom-left\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nesw-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"bm\": // Bottom-middle\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.left = \"50%\";\n\t\t\t\t\thandle.style.marginLeft = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ns-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"br\": // Bottom-right\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nwse-resize\";\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Ajouter l'écouteur d'événement\n\t\t\thandle.addEventListener(\"mousedown\", (e) =>\n\t\t\t\tthis._handleCropHandleMouseDown(e, handleType),\n\t\t\t);\n\n\t\t\toverlay.appendChild(handle);\n\t\t}\n\n\t\t// Ajouter l'écouteur pour le déplacement de l'overlay\n\t\toverlay.addEventListener(\n\t\t\t\"mousedown\",\n\t\t\tthis._handleCropOverlayMouseDown.bind(this),\n\t\t);\n\n\t\tthis.imageElement.parentNode.appendChild(overlay);\n\t\tthis.state.cropOverlay = overlay;\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur une poignée de redimensionnement\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t * @param {string} handleType - Type de poignée\n\t */\n\t_handleCropHandleMouseDown(e, handleType) {\n\t\tthis.interaction.cropResizing = true;\n\t\tthis.interaction.activeHandle = handleType;\n\n\t\t// Enregistrer les dimensions et position initiales\n\t\tthis.interaction.startX =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.left, 10) || 0;\n\t\tthis.interaction.startY =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.top, 10) || 0;\n\t\tthis.interaction.startWidth = this.state.cropOverlay.offsetWidth;\n\t\tthis.interaction.startHeight = this.state.cropOverlay.offsetHeight;\n\t\tthis.interaction.startMouseX = e.clientX;\n\t\tthis.interaction.startMouseY = e.clientY;\n\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t */\n\t_handleCropOverlayMouseDown(e) {\n\t\t// Ignorer si on clique sur une poignée\n\t\tif (e.target !== this.state.cropOverlay) return;\n\n\t\tthis.interaction.cropDragging = true;\n\t\tthis.state.cropOverlay.style.cursor = \"grabbing\";\n\n\t\t// Enregistrer la position initiale\n\t\tthis.interaction.startX =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.left, 10) || 0;\n\t\tthis.interaction.startY =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.top, 10) || 0;\n\t\tthis.interaction.startMouseX = e.clientX;\n\t\tthis.interaction.startMouseY = e.clientY;\n\n\t\te.preventDefault();\n\t}\n\n\t/**\n\t * Configure les écouteurs d'événements globaux\n\t * @private\n\t */\n\t_setupEventListeners() {\n\t\t// Écouteur pour le redimensionnement de la fenêtre\n\t\twindow.addEventListener(\"resize\", this._updateScaling.bind(this));\n\n\t\t// Écouteur pour le chargement de l'image\n\t\tif (!this.imageElement.complete) {\n\t\t\tthis.imageElement.addEventListener(\n\t\t\t\t\"load\",\n\t\t\t\tthis._updateScaling.bind(this),\n\t\t\t);\n\t\t}\n\n\t\t// Écouteurs pour les interactions de souris\n\t\tdocument.addEventListener(\"mouseup\", this._handleMouseUp.bind(this));\n\t\tdocument.addEventListener(\"mousemove\", this._handleMouseMove.bind(this));\n\t}\n\n\t/**\n\t * Gère l'événement mouseup global\n\t * @private\n\t */\n\t_handleMouseUp() {\n\t\tif (this.interaction.focusDragging) {\n\t\t\tthis.interaction.focusDragging = false;\n\t\t\tif (this.state.focusMarker) this.state.focusMarker.style.cursor = \"move\";\n\t\t}\n\n\t\tif (this.interaction.cropDragging) {\n\t\t\tthis.interaction.cropDragging = false;\n\t\t\tif (this.state.cropOverlay) this.state.cropOverlay.style.cursor = \"move\";\n\t\t}\n\n\t\tthis.interaction.cropResizing = false;\n\t\tthis.interaction.activeHandle = null;\n\t\tdocument.body.style.cursor = \"default\";\n\t}\n\n\t/**\n\t * Gère l'événement mousemove global\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleMouseMove(e) {\n\t\t// Gestion du déplacement du point focal\n\t\tif (this.interaction.focusDragging && this.state.focusMarker) {\n\t\t\tthis._handleFocusMarkerDrag(e);\n\t\t}\n\n\t\t// Gestion du déplacement de la zone de recadrage\n\t\tif (this.interaction.cropDragging) {\n\t\t\tthis._handleCropOverlayDrag(e);\n\t\t}\n\n\t\t// Gestion du redimensionnement de la zone de recadrage\n\t\tif (this.interaction.cropResizing) {\n\t\t\tthis._handleCropOverlayResize(e);\n\t\t}\n\t}\n\n\t/**\n\t * Gère le déplacement du marqueur de point focal\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleFocusMarkerDrag(e) {\n\t\tconst imageRect = this.imageElement.getBoundingClientRect();\n\n\t\t// Calculer la position cible relative à l'image\n\t\tconst targetScaledX =\n\t\t\te.clientX - imageRect.left - this.interaction.focusDragOffsetX;\n\t\tconst targetScaledY =\n\t\t\te.clientY - imageRect.top - this.interaction.focusDragOffsetY;\n\n\t\t// Convertir en coordonnées originales\n\t\tconst original = this._toOriginalCoords(targetScaledX, targetScaledY);\n\n\t\t// Mettre à jour le point focal\n\t\tthis.setFocusPoint(original.x, original.y);\n\t}\n\n\t/**\n\t * Gère le déplacement de l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleCropOverlayDrag(e) {\n\t\tconst deltaX = e.clientX - this.interaction.startMouseX;\n\t\tconst deltaY = e.clientY - this.interaction.startMouseY;\n\n\t\t// Calculer la nouvelle position en pixels d'affichage\n\t\tconst newX = this.interaction.startX + deltaX;\n\t\tconst newY = this.interaction.startY + deltaY;\n\n\t\t// Convertir en coordonnées originales\n\t\tconst original = this._toOriginalCoords(newX, newY);\n\n\t\t// Obtenir les dimensions actuelles en coordonnées originales\n\t\tconst { width, height } = this.state.cropZone;\n\n\t\t// Mettre à jour la zone de recadrage\n\t\tthis.setCropZone(original.x, original.y, width, height);\n\t}\n\n\t/**\n\t * Gère le redimensionnement de l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleCropOverlayResize(e) {\n\t\tif (!this.interaction.activeHandle) return;\n\n\t\tconst deltaX = e.clientX - this.interaction.startMouseX;\n\t\tconst deltaY = e.clientY - this.interaction.startMouseY;\n\n\t\tlet newX = this.interaction.startX;\n\t\tlet newY = this.interaction.startY;\n\t\tlet newWidth = this.interaction.startWidth;\n\t\tlet newHeight = this.interaction.startHeight;\n\n\t\t// Ajuster en fonction de la poignée active\n\t\tif (this.interaction.activeHandle.includes(\"t\")) {\n\t\t\t// Top\n\t\t\tnewY = this.interaction.startY + deltaY;\n\t\t\tnewHeight = this.interaction.startHeight - deltaY;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"b\")) {\n\t\t\t// Bottom\n\t\t\tnewHeight = this.interaction.startHeight + deltaY;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"l\")) {\n\t\t\t// Left\n\t\t\tnewX = this.interaction.startX + deltaX;\n\t\t\tnewWidth = this.interaction.startWidth - deltaX;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"r\")) {\n\t\t\t// Right\n\t\t\tnewWidth = this.interaction.startWidth + deltaX;\n\t\t}\n\n\t\t// Empêcher les dimensions négatives\n\t\tif (newWidth < 10) {\n\t\t\tif (this.interaction.activeHandle.includes(\"l\")) {\n\t\t\t\tnewX = this.interaction.startX + this.interaction.startWidth - 10;\n\t\t\t}\n\t\t\tnewWidth = 10;\n\t\t}\n\t\tif (newHeight < 10) {\n\t\t\tif (this.interaction.activeHandle.includes(\"t\")) {\n\t\t\t\tnewY = this.interaction.startY + this.interaction.startHeight - 10;\n\t\t\t}\n\t\t\tnewHeight = 10;\n\t\t}\n\n\t\t// Convertir les coordonnées d'affichage en coordonnées originales\n\t\tconst originalX = newX / this.state.scaleX;\n\t\tconst originalY = newY / this.state.scaleY;\n\t\tconst originalWidth = newWidth / this.state.scaleX;\n\t\tconst originalHeight = newHeight / this.state.scaleY;\n\n\t\t// Mettre à jour la zone de recadrage\n\t\tthis.setCropZone(originalX, originalY, originalWidth, originalHeight);\n\t}\n\n\t/**\n\t * Met à jour la position du marqueur de point focal\n\t * @private\n\t */\n\t_updateFocusMarkerPosition() {\n\t\tif (!this.state.focusMarker) return;\n\n\t\tconst { x, y } = this.state.focusPoint;\n\n\t\t// Limiter les coordonnées aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n\t\tconst clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n\n\t\t// Mettre à jour l'état si les coordonnées ont été limitées\n\t\tif (x !== clampedX || y !== clampedY) {\n\t\t\tthis.state.focusPoint = { x: clampedX, y: clampedY };\n\t\t}\n\n\t\tconst scaled = this._toScaledCoords(clampedX, clampedY);\n\n\t\t// LOGGING: Validate padding offset\n\t\tif (this.options.debug) {\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tconst paddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t\tconsole.log(\n\t\t\t\t\"[FocusMarker] scaled:\",\n\t\t\t\tscaled,\n\t\t\t\t\"paddingLeft:\",\n\t\t\t\tpaddingLeft,\n\t\t\t\t\"paddingTop:\",\n\t\t\t\tpaddingTop,\n\t\t\t\t\"containerRect:\",\n\t\t\t\tcontainer.getBoundingClientRect(),\n\t\t\t);\n\t\t}\n\n\t\t// Ajuster pour centrer le marqueur\n\t\t// Adjust for container padding (use unique variable names)\n\t\tlet focusPaddingLeft = 0;\n\t\tlet focusPaddingTop = 0;\n\t\t{\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tfocusPaddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tfocusPaddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t}\n\n\t\tthis.state.focusMarker.style.left = `${\n\t\t\tscaled.x + focusPaddingLeft - this.state.focusMarker.offsetWidth / 2\n\t\t}px`;\n\t\tthis.state.focusMarker.style.top = `${\n\t\t\tscaled.y + focusPaddingTop - this.state.focusMarker.offsetHeight / 2\n\t\t}px`;\n\t\tif (this.options.debug) {\n\t\t\tconsole.log(\n\t\t\t\t\"[FocusMarker] style.left:\",\n\t\t\t\tthis.state.focusMarker.style.left,\n\t\t\t\t\"style.top:\",\n\t\t\t\tthis.state.focusMarker.style.top,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Met à jour la position et les dimensions de l'overlay de recadrage\n\t * @private\n\t */\n\t_updateCropOverlayPosition() {\n\t\tif (!this.state.cropOverlay) return;\n\n\t\tconst { x, y, width, height } = this.state.cropZone;\n\n\t\t// Limiter aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n\t\tconst clampedY = Math.max(\n\t\t\t0,\n\t\t\tMath.min(y, this.state.originalHeight - height),\n\t\t);\n\t\tconst clampedWidth = Math.max(\n\t\t\t10,\n\t\t\tMath.min(width, this.state.originalWidth - clampedX),\n\t\t);\n\t\tconst clampedHeight = Math.max(\n\t\t\t10,\n\t\t\tMath.min(height, this.state.originalHeight - clampedY),\n\t\t);\n\n\t\t// Mettre à jour l'état si les valeurs ont été limitées\n\t\tif (\n\t\t\tx !== clampedX ||\n\t\t\ty !== clampedY ||\n\t\t\twidth !== clampedWidth ||\n\t\t\theight !== clampedHeight\n\t\t) {\n\t\t\tthis.state.cropZone = {\n\t\t\t\tx: clampedX,\n\t\t\t\ty: clampedY,\n\t\t\t\twidth: clampedWidth,\n\t\t\t\theight: clampedHeight,\n\t\t\t};\n\t\t}\n\n\t\t// Convertir en coordonnées d'affichage\n\t\tconst scaled = this._toScaledCoords(clampedX, clampedY);\n\t\tconst scaledWidth = clampedWidth * this.state.scaleX;\n\t\tconst scaledHeight = clampedHeight * this.state.scaleY;\n\n\t\t// LOGGING: Validate padding offset\n\t\tif (this.options.debug) {\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tconst paddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t\tconsole.log(\n\t\t\t\t\"[CropOverlay] scaled:\",\n\t\t\t\tscaled,\n\t\t\t\t\"paddingLeft:\",\n\t\t\t\tpaddingLeft,\n\t\t\t\t\"paddingTop:\",\n\t\t\t\tpaddingTop,\n\t\t\t\t\"containerRect:\",\n\t\t\t\tcontainer.getBoundingClientRect(),\n\t\t\t);\n\t\t}\n\n\t\t// Mettre à jour l'overlay\n\t\t// Adjust for container padding (use unique variable names)\n\t\tlet cropPaddingLeft = 0;\n\t\tlet cropPaddingTop = 0;\n\t\t{\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tcropPaddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tcropPaddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t}\n\n\t\tthis.state.cropOverlay.style.left = `${scaled.x + cropPaddingLeft}px`;\n\t\tthis.state.cropOverlay.style.top = `${scaled.y + cropPaddingTop}px`;\n\t\tthis.state.cropOverlay.style.width = `${scaledWidth}px`;\n\t\tthis.state.cropOverlay.style.height = `${scaledHeight}px`;\n\t\tif (this.options.debug) {\n\t\t\tconsole.log(\n\t\t\t\t\"[CropOverlay] style.left:\",\n\t\t\t\tthis.state.cropOverlay.style.left,\n\t\t\t\t\"style.top:\",\n\t\t\t\tthis.state.cropOverlay.style.top,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Active ou désactive le point focal\n\t * @public\n\t * @param {boolean} active - État d'activation\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\ttoggleFocusPoint(active) {\n\t\tif (!this.options.focusPoint.enabled) return this;\n\n\t\tconst isActive = active === undefined ? !this.state.focusActive : active;\n\n\t\tif (active && !this.state.focusActive) {\n\t\t\t// Activer le point focal\n\t\t\tif (!this.state.focusMarker) {\n\t\t\t\tthis._createFocusMarker();\n\t\t\t}\n\n\t\t\t// Positionner au centre de l'image par défaut si pas déjà défini\n\t\t\tif (this.state.focusPoint.x === 0 && this.state.focusPoint.y === 0) {\n\t\t\t\tthis.state.focusPoint = {\n\t\t\t\t\tx: this.state.originalWidth / 2,\n\t\t\t\t\ty: this.state.originalHeight / 2,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t\tthis.state.focusMarker.style.display = \"block\";\n\t\t\tthis.state.focusActive = true;\n\t\t} else if (!active && this.state.focusActive) {\n\t\t\t// Désactiver le point focal\n\t\t\tif (this.state.focusMarker) {\n\t\t\t\tthis.state.focusMarker.style.display = \"none\";\n\t\t\t}\n\t\t\tthis.state.focusActive = false;\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Active ou désactive la zone de recadrage\n\t * @public\n\t * @param {boolean} active - État d'activation\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\ttoggleCropZone(active) {\n\t\tif (!this.options.cropZone.enabled) return this;\n\n\t\tconst isActive = active === undefined ? !this.state.cropActive : active;\n\n\t\tif (active && !this.state.cropActive) {\n\t\t\t// Activer la zone de recadrage\n\t\t\tif (!this.state.cropOverlay) {\n\t\t\t\tthis._createCropOverlay();\n\t\t\t}\n\n\t\t\t// Définir une zone par défaut si pas déjà définie\n\t\t\tif (this.state.cropZone.width === 0 || this.state.cropZone.height === 0) {\n\t\t\t\tconst defaultWidth = this.state.originalWidth / 2;\n\t\t\t\tconst defaultHeight = this.state.originalHeight / 2;\n\t\t\t\tconst defaultX = (this.state.originalWidth - defaultWidth) / 2;\n\t\t\t\tconst defaultY = (this.state.originalHeight - defaultHeight) / 2;\n\n\t\t\t\tthis.state.cropZone = {\n\t\t\t\t\tx: defaultX,\n\t\t\t\t\ty: defaultY,\n\t\t\t\t\twidth: defaultWidth,\n\t\t\t\t\theight: defaultHeight,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis._updateCropOverlayPosition();\n\t\t\tthis.state.cropOverlay.style.display = \"block\";\n\t\t\tthis.state.cropActive = true;\n\t\t} else if (!active && this.state.cropActive) {\n\t\t\t// Désactiver la zone de recadrage\n\t\t\tif (this.state.cropOverlay) {\n\t\t\t\tthis.state.cropOverlay.style.display = \"none\";\n\t\t\t}\n\t\t\tthis.state.cropActive = false;\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Définit la position du point focal\n\t * @public\n\t * @param {number} x - Coordonnée X en pixels originaux\n\t * @param {number} y - Coordonnée Y en pixels originaux\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\tsetFocusPoint(x, y) {\n\t\t// Limiter les coordonnées aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n\t\tconst clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n\n\t\tthis.state.focusPoint = { x: clampedX, y: clampedY };\n\n\t\tif (this.state.focusActive && this.state.focusMarker) {\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Définit la position et les dimensions de la zone de recadrage\n\t * @public\n\t * @param {number} x - Coordonnée X en pixels originaux\n\t * @param {number} y - Coordonnée Y en pixels originaux\n\t * @param {number} width - Largeur en pixels originaux\n\t * @param {number} height - Hauteur en pixels originaux\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\tsetCropZone(x, y, width, height) {\n\t\t// Limiter aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n\t\tconst clampedY = Math.max(\n\t\t\t0,\n\t\t\tMath.min(y, this.state.originalHeight - height),\n\t\t);\n\t\tconst clampedWidth = Math.max(\n\t\t\t10,\n\t\t\tMath.min(width, this.state.originalWidth - clampedX),\n\t\t);\n\t\tconst clampedHeight = Math.max(\n\t\t\t10,\n\t\t\tMath.min(height, this.state.originalHeight - clampedY),\n\t\t);\n\n\t\tthis.state.cropZone = {\n\t\t\tx: clampedX,\n\t\t\ty: clampedY,\n\t\t\twidth: clampedWidth,\n\t\t\theight: clampedHeight,\n\t\t};\n\n\t\tif (this.state.cropActive && this.state.cropOverlay) {\n\t\t\tthis._updateCropOverlayPosition();\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Obtient la position actuelle du point focal\n\t * @public\n\t * @returns {Object} Coordonnées du point focal {x, y}\n\t */\n\tgetFocusPoint() {\n\t\treturn { ...this.state.focusPoint };\n\t}\n\n\t/**\n\t * Obtient la position et les dimensions actuelles de la zone de recadrage\n\t * @public\n\t * @returns {Object} Zone de recadrage {x, y, width, height}\n\t */\n\tgetCropZone() {\n\t\treturn { ...this.state.cropZone };\n\t}\n\n\t/**\n\t * Obtient les dimensions originales de l'image\n\t * @public\n\t * @returns {Object} Dimensions {width, height}\n\t */\n\tgetImageDimensions() {\n\t\treturn {\n\t\t\twidth: this.state.originalWidth,\n\t\t\theight: this.state.originalHeight,\n\t\t};\n\t}\n\n\t/**\n\t * Notifie les changements via le callback\n\t * @private\n\t */\n\t_notifyChange() {\n\t\tif (typeof this.options.onChange === \"function\") {\n\t\t\tthis.options.onChange({\n\t\t\t\tfocusPoint: this.getFocusPoint(),\n\t\t\t\tcropZone: this.getCropZone(),\n\t\t\t\tfocusActive: this.state.focusActive,\n\t\t\t\tcropActive: this.state.cropActive,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Détruit l'instance et nettoie les ressources\n\t * @public\n\t */\n\tdestroy() {\n\t\t// Supprimer les éléments DOM\n\t\tif (this.state.focusMarker?.parentNode) {\n\t\t\tthis.state.focusMarker.parentNode.removeChild(this.state.focusMarker);\n\t\t}\n\n\t\tif (this.state.cropOverlay?.parentNode) {\n\t\t\tthis.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay);\n\t\t}\n\n\t\t// Supprimer les écouteurs d'événements\n\t\twindow.removeEventListener(\"resize\", this._updateScaling.bind(this));\n\t\tdocument.removeEventListener(\"mouseup\", this._handleMouseUp.bind(this));\n\t\tdocument.removeEventListener(\"mousemove\", this._handleMouseMove.bind(this));\n\n\t\t// Réinitialiser l'état\n\t\tthis.state = null;\n\t\tthis.interaction = null;\n\t\tthis.options = null;\n\t\tthis.imageElement = null;\n\t}\n}\n\n// Exporter la classe\nexport default VisualImageTool;\n","/**\n * Point d'entrée principal pour le package image-tool\n * Exporte la classe VisualImageTool\n */\n\nimport VisualImageTool from \"./visual-image-tool.js\";\n\n// Exporter la classe comme export par défaut\nexport default VisualImageTool;\n\n// Exporter également comme export nommé pour plus de flexibilité\nexport { VisualImageTool };\n"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).VisualImageTool={})}(this,(function(t){"use strict";class e{constructor(t){if(!t||!t.imageElement)throw new Error("L'élément image est requis");if(this.imageElement="string"==typeof t.imageElement?document.querySelector(t.imageElement):t.imageElement,!this.imageElement||"IMG"!==this.imageElement.tagName)throw new Error("Élément image invalide");this.options={focusPoint:{enabled:!0,style:{width:"30px",height:"30px",border:"3px solid white",boxShadow:"0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)",backgroundColor:"rgba(255, 0, 0, 0.5)"},...t.focusPoint},cropZone:{enabled:!0,style:{border:"1px dashed #fff",backgroundColor:"rgba(0, 0, 0, 0.4)"},handleStyle:{width:"14px",height:"14px",backgroundColor:"white",border:"2px solid black",boxShadow:"0 0 3px rgba(0,0,0,0.5)"},...t.cropZone},onChange:t.onChange||(()=>{}),debug:t.debug||!1},this.state={focusMarker:null,cropOverlay:null,focusActive:!1,cropActive:!1,focusPoint:{x:0,y:0},cropZone:{x:0,y:0,width:0,height:0},originalWidth:1,originalHeight:1,displayWidth:1,displayHeight:1,scaleX:1,scaleY:1},this.interaction={focusDragging:!1,focusDragOffsetX:0,focusDragOffsetY:0,cropDragging:!1,cropResizing:!1,activeHandle:null,startX:0,startY:0,startWidth:0,startHeight:0,startMouseX:0,startMouseY:0},this._init()}_init(){this._prepareContainer(),this._updateScaling(),this.options.focusPoint.enabled&&this._createFocusMarker(),this.options.cropZone.enabled&&this._createCropOverlay(),this._setupEventListeners()}_prepareContainer(){this.imageElement.parentNode&&(this.imageElement.parentNode.style.position="relative")}_updateScaling(){this.state.originalWidth=this.imageElement.naturalWidth||1,this.state.originalHeight=this.imageElement.naturalHeight||1,this.state.displayWidth=this.imageElement.offsetWidth,this.state.displayHeight=this.imageElement.offsetHeight,this.state.scaleX=this.state.displayWidth/this.state.originalWidth,this.state.scaleY=this.state.displayHeight/this.state.originalHeight,this.state.focusActive&&this._updateFocusMarkerPosition(),this.state.cropActive&&this._updateCropOverlayPosition()}_toOriginalCoords(t,e){return{x:t/this.state.scaleX,y:e/this.state.scaleY}}_toScaledCoords(t,e){return{x:t*this.state.scaleX,y:e*this.state.scaleY}}_createFocusMarker(){if(this.state.focusMarker)return;const t=document.createElement("div");t.style.position="absolute",t.style.width=this.options.focusPoint.style.width,t.style.height=this.options.focusPoint.style.height,t.style.border=this.options.focusPoint.style.border,t.style.boxShadow=this.options.focusPoint.style.boxShadow,t.style.backgroundColor=this.options.focusPoint.style.backgroundColor,t.style.cursor="move",t.style.display="none",t.style.zIndex="999",t.style.clipPath="polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)",this.imageElement.parentNode.appendChild(t),this.state.focusMarker=t,t.addEventListener("mousedown",this._handleFocusMarkerMouseDown.bind(this))}_handleFocusMarkerMouseDown(t){this.interaction.focusDragging=!0,this.state.focusMarker.style.cursor="grabbing";const e=this.state.focusMarker.getBoundingClientRect();this.interaction.focusDragOffsetX=t.clientX-(e.left+e.width/2),this.interaction.focusDragOffsetY=t.clientY-(e.top+e.height/2),t.preventDefault()}_createCropOverlay(){if(this.state.cropOverlay)return;const t=document.createElement("div");t.style.position="absolute",t.style.border=this.options.cropZone.style.border,t.style.backgroundColor=this.options.cropZone.style.backgroundColor,t.style.boxSizing="border-box",t.style.cursor="move",t.style.display="none",t.style.zIndex="998";["tl","tm","tr","ml","mr","bl","bm","br"].forEach((e=>{const i=document.createElement("div");switch(i.style.position="absolute",i.style.width=this.options.cropZone.handleStyle.width,i.style.height=this.options.cropZone.handleStyle.height,i.style.backgroundColor=this.options.cropZone.handleStyle.backgroundColor,i.style.border=this.options.cropZone.handleStyle.border,i.style.boxShadow=this.options.cropZone.handleStyle.boxShadow,i.style.boxSizing="border-box",i.dataset.handle=e,e){case"tl":i.style.top="-7px",i.style.left="-7px",i.style.cursor="nwse-resize";break;case"tm":i.style.top="-7px",i.style.left="50%",i.style.marginLeft="-7px",i.style.cursor="ns-resize";break;case"tr":i.style.top="-7px",i.style.right="-7px",i.style.cursor="nesw-resize";break;case"ml":i.style.top="50%",i.style.left="-7px",i.style.marginTop="-7px",i.style.cursor="ew-resize";break;case"mr":i.style.top="50%",i.style.right="-7px",i.style.marginTop="-7px",i.style.cursor="ew-resize";break;case"bl":i.style.bottom="-7px",i.style.left="-7px",i.style.cursor="nesw-resize";break;case"bm":i.style.bottom="-7px",i.style.left="50%",i.style.marginLeft="-7px",i.style.cursor="ns-resize";break;case"br":i.style.bottom="-7px",i.style.right="-7px",i.style.cursor="nwse-resize"}i.addEventListener("mousedown",(t=>this._handleCropHandleMouseDown(t,e))),t.appendChild(i)})),t.addEventListener("mousedown",this._handleCropOverlayMouseDown.bind(this)),this.imageElement.parentNode.appendChild(t),this.state.cropOverlay=t}_handleCropHandleMouseDown(t,e){this.interaction.cropResizing=!0,this.interaction.activeHandle=e,this.interaction.startX=parseInt(this.state.cropOverlay.style.left,10)||0,this.interaction.startY=parseInt(this.state.cropOverlay.style.top,10)||0,this.interaction.startWidth=this.state.cropOverlay.offsetWidth,this.interaction.startHeight=this.state.cropOverlay.offsetHeight,this.interaction.startMouseX=t.clientX,this.interaction.startMouseY=t.clientY,t.preventDefault(),t.stopPropagation()}_handleCropOverlayMouseDown(t){t.target===this.state.cropOverlay&&(this.interaction.cropDragging=!0,this.state.cropOverlay.style.cursor="grabbing",this.interaction.startX=parseInt(this.state.cropOverlay.style.left,10)||0,this.interaction.startY=parseInt(this.state.cropOverlay.style.top,10)||0,this.interaction.startMouseX=t.clientX,this.interaction.startMouseY=t.clientY,t.preventDefault())}_setupEventListeners(){window.addEventListener("resize",this._updateScaling.bind(this)),this.imageElement.complete||this.imageElement.addEventListener("load",this._updateScaling.bind(this)),document.addEventListener("mouseup",this._handleMouseUp.bind(this)),document.addEventListener("mousemove",this._handleMouseMove.bind(this))}_handleMouseUp(){this.interaction.focusDragging&&(this.interaction.focusDragging=!1,this.state.focusMarker&&(this.state.focusMarker.style.cursor="move")),this.interaction.cropDragging&&(this.interaction.cropDragging=!1,this.state.cropOverlay&&(this.state.cropOverlay.style.cursor="move")),this.interaction.cropResizing=!1,this.interaction.activeHandle=null,document.body.style.cursor="default"}_handleMouseMove(t){this.interaction.focusDragging&&this.state.focusMarker&&this._handleFocusMarkerDrag(t),this.interaction.cropDragging&&this._handleCropOverlayDrag(t),this.interaction.cropResizing&&this._handleCropOverlayResize(t)}_handleFocusMarkerDrag(t){const e=this.imageElement.getBoundingClientRect(),i=t.clientX-e.left-this.interaction.focusDragOffsetX,s=t.clientY-e.top-this.interaction.focusDragOffsetY,o=this._toOriginalCoords(i,s);this.setFocusPoint(o.x,o.y)}_handleCropOverlayDrag(t){const e=t.clientX-this.interaction.startMouseX,i=t.clientY-this.interaction.startMouseY;let s=this.interaction.startX+e,o=this.interaction.startY+i;const a=this._toOriginalCoords(s,o),{width:n,height:r}=this.state.cropZone;this.setCropZone(a.x,a.y,n,r)}_handleCropOverlayResize(t){if(!this.interaction.activeHandle)return;const e=t.clientX-this.interaction.startMouseX,i=t.clientY-this.interaction.startMouseY;let s=this.interaction.startX,o=this.interaction.startY,a=this.interaction.startWidth,n=this.interaction.startHeight;this.interaction.activeHandle.includes("t")&&(o=this.interaction.startY+i,n=this.interaction.startHeight-i),this.interaction.activeHandle.includes("b")&&(n=this.interaction.startHeight+i),this.interaction.activeHandle.includes("l")&&(s=this.interaction.startX+e,a=this.interaction.startWidth-e),this.interaction.activeHandle.includes("r")&&(a=this.interaction.startWidth+e),a<10&&(this.interaction.activeHandle.includes("l")&&(s=this.interaction.startX+this.interaction.startWidth-10),a=10),n<10&&(this.interaction.activeHandle.includes("t")&&(o=this.interaction.startY+this.interaction.startHeight-10),n=10);const r=s/this.state.scaleX,h=o/this.state.scaleY,l=a/this.state.scaleX,c=n/this.state.scaleY;this.setCropZone(r,h,l,c)}_updateFocusMarkerPosition(){if(!this.state.focusMarker)return;const{x:t,y:e}=this.state.focusPoint,i=Math.max(0,Math.min(t,this.state.originalWidth)),s=Math.max(0,Math.min(e,this.state.originalHeight));t===i&&e===s||(this.state.focusPoint={x:i,y:s});const o=this._toScaledCoords(i,s);if(this.options.debug){const t=this.imageElement.parentNode,e=window.getComputedStyle(t),i=parseFloat(e.paddingLeft),s=parseFloat(e.paddingTop);console.log("[FocusMarker] scaled:",o,"paddingLeft:",i,"paddingTop:",s,"containerRect:",t.getBoundingClientRect())}let a=0,n=0;{const t=this.imageElement.parentNode,e=window.getComputedStyle(t);a=parseFloat(e.paddingLeft),n=parseFloat(e.paddingTop)}this.state.focusMarker.style.left=o.x+a-this.state.focusMarker.offsetWidth/2+"px",this.state.focusMarker.style.top=o.y+n-this.state.focusMarker.offsetHeight/2+"px",this.options.debug&&console.log("[FocusMarker] style.left:",this.state.focusMarker.style.left,"style.top:",this.state.focusMarker.style.top)}_updateCropOverlayPosition(){if(!this.state.cropOverlay)return;const{x:t,y:e,width:i,height:s}=this.state.cropZone,o=Math.max(0,Math.min(t,this.state.originalWidth-i)),a=Math.max(0,Math.min(e,this.state.originalHeight-s)),n=Math.max(10,Math.min(i,this.state.originalWidth-o)),r=Math.max(10,Math.min(s,this.state.originalHeight-a));t===o&&e===a&&i===n&&s===r||(this.state.cropZone={x:o,y:a,width:n,height:r});const h=this._toScaledCoords(o,a),l=n*this.state.scaleX,c=r*this.state.scaleY;if(this.options.debug){const t=this.imageElement.parentNode,e=window.getComputedStyle(t),i=parseFloat(e.paddingLeft),s=parseFloat(e.paddingTop);console.log("[CropOverlay] scaled:",h,"paddingLeft:",i,"paddingTop:",s,"containerRect:",t.getBoundingClientRect())}let d=0,p=0;{const t=this.imageElement.parentNode,e=window.getComputedStyle(t);d=parseFloat(e.paddingLeft),p=parseFloat(e.paddingTop)}this.state.cropOverlay.style.left=h.x+d+"px",this.state.cropOverlay.style.top=h.y+p+"px",this.state.cropOverlay.style.width=l+"px",this.state.cropOverlay.style.height=c+"px",this.options.debug&&console.log("[CropOverlay] style.left:",this.state.cropOverlay.style.left,"style.top:",this.state.cropOverlay.style.top)}toggleFocusPoint(t){return this.options.focusPoint.enabled?(void 0===t&&(t=!this.state.focusActive),t&&!this.state.focusActive?(this.state.focusMarker||this._createFocusMarker(),0===this.state.focusPoint.x&&0===this.state.focusPoint.y&&(this.state.focusPoint={x:this.state.originalWidth/2,y:this.state.originalHeight/2}),this._updateFocusMarkerPosition(),this.state.focusMarker.style.display="block",this.state.focusActive=!0):!t&&this.state.focusActive&&(this.state.focusMarker&&(this.state.focusMarker.style.display="none"),this.state.focusActive=!1),this._notifyChange(),this):this}toggleCropZone(t){if(!this.options.cropZone.enabled)return this;if(void 0===t&&(t=!this.state.cropActive),t&&!this.state.cropActive){if(this.state.cropOverlay||this._createCropOverlay(),0===this.state.cropZone.width||0===this.state.cropZone.height){const t=this.state.originalWidth/2,e=this.state.originalHeight/2,i=(this.state.originalWidth-t)/2,s=(this.state.originalHeight-e)/2;this.state.cropZone={x:i,y:s,width:t,height:e}}this._updateCropOverlayPosition(),this.state.cropOverlay.style.display="block",this.state.cropActive=!0}else!t&&this.state.cropActive&&(this.state.cropOverlay&&(this.state.cropOverlay.style.display="none"),this.state.cropActive=!1);return this._notifyChange(),this}setFocusPoint(t,e){const i=Math.max(0,Math.min(t,this.state.originalWidth)),s=Math.max(0,Math.min(e,this.state.originalHeight));return this.state.focusPoint={x:i,y:s},this.state.focusActive&&this.state.focusMarker&&this._updateFocusMarkerPosition(),this._notifyChange(),this}setCropZone(t,e,i,s){const o=Math.max(0,Math.min(t,this.state.originalWidth-i)),a=Math.max(0,Math.min(e,this.state.originalHeight-s)),n=Math.max(10,Math.min(i,this.state.originalWidth-o)),r=Math.max(10,Math.min(s,this.state.originalHeight-a));return this.state.cropZone={x:o,y:a,width:n,height:r},this.state.cropActive&&this.state.cropOverlay&&this._updateCropOverlayPosition(),this._notifyChange(),this}getFocusPoint(){return{...this.state.focusPoint}}getCropZone(){return{...this.state.cropZone}}getImageDimensions(){return{width:this.state.originalWidth,height:this.state.originalHeight}}_notifyChange(){"function"==typeof this.options.onChange&&this.options.onChange({focusPoint:this.getFocusPoint(),cropZone:this.getCropZone(),focusActive:this.state.focusActive,cropActive:this.state.cropActive})}destroy(){this.state.focusMarker&&this.state.focusMarker.parentNode&&this.state.focusMarker.parentNode.removeChild(this.state.focusMarker),this.state.cropOverlay&&this.state.cropOverlay.parentNode&&this.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay),window.removeEventListener("resize",this._updateScaling.bind(this)),document.removeEventListener("mouseup",this._handleMouseUp.bind(this)),document.removeEventListener("mousemove",this._handleMouseMove.bind(this)),this.state=null,this.interaction=null,this.options=null,this.imageElement=null}}t.VisualImageTool=e,t.default=e,Object.defineProperty(t,"__esModule",{value:!0})}));
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).VisualImageTool={})}(this,(function(t){"use strict";class e{constructor(t){if(!t||!t.imageElement)throw new Error("L'élément image est requis");if(this.imageElement="string"==typeof t.imageElement?document.querySelector(t.imageElement):t.imageElement,!this.imageElement||"IMG"!==this.imageElement.tagName)throw new Error("Élément image invalide");this.options={focusPoint:{enabled:!0,style:{width:"30px",height:"30px",border:"3px solid white",boxShadow:"0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)",backgroundColor:"rgba(255, 0, 0, 0.5)"},...t.focusPoint},cropZone:{enabled:!0,style:{border:"1px dashed #fff",backgroundColor:"rgba(0, 0, 0, 0.4)"},handleStyle:{width:"14px",height:"14px",backgroundColor:"white",border:"2px solid black",boxShadow:"0 0 3px rgba(0,0,0,0.5)"},...t.cropZone},onChange:t.onChange||(()=>{}),debug:t.debug||!1},this.state={focusMarker:null,cropOverlay:null,focusActive:!1,cropActive:!1,focusPoint:{x:0,y:0},cropZone:{x:0,y:0,width:0,height:0},originalWidth:1,originalHeight:1,displayWidth:1,displayHeight:1,scaleX:1,scaleY:1},this.interaction={focusDragging:!1,focusDragOffsetX:0,focusDragOffsetY:0,cropDragging:!1,cropResizing:!1,activeHandle:null,startX:0,startY:0,startWidth:0,startHeight:0,startMouseX:0,startMouseY:0},this._init()}_init(){this._prepareContainer(),this._updateScaling(),this.options.focusPoint.enabled&&this._createFocusMarker(),this.options.cropZone.enabled&&this._createCropOverlay(),this._setupEventListeners()}_prepareContainer(){this.imageElement.parentNode&&(this.imageElement.parentNode.style.position="relative")}_updateScaling(){this.state.originalWidth=this.imageElement.naturalWidth||1,this.state.originalHeight=this.imageElement.naturalHeight||1,this.state.displayWidth=this.imageElement.offsetWidth,this.state.displayHeight=this.imageElement.offsetHeight,this.state.scaleX=this.state.displayWidth/this.state.originalWidth,this.state.scaleY=this.state.displayHeight/this.state.originalHeight,this.state.focusActive&&this._updateFocusMarkerPosition(),this.state.cropActive&&this._updateCropOverlayPosition()}_toOriginalCoords(t,e){return{x:t/this.state.scaleX,y:e/this.state.scaleY}}_toScaledCoords(t,e){return{x:t*this.state.scaleX,y:e*this.state.scaleY}}_createFocusMarker(){if(this.state.focusMarker)return;const t=document.createElement("div");t.style.position="absolute",t.style.width=this.options.focusPoint.style.width,t.style.height=this.options.focusPoint.style.height,t.style.border=this.options.focusPoint.style.border,t.style.boxShadow=this.options.focusPoint.style.boxShadow,t.style.backgroundColor=this.options.focusPoint.style.backgroundColor,t.style.cursor="move",t.style.display="none",t.style.zIndex="999",t.style.clipPath="polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)",this.imageElement.parentNode.appendChild(t),this.state.focusMarker=t,t.addEventListener("mousedown",this._handleFocusMarkerMouseDown.bind(this))}_handleFocusMarkerMouseDown(t){this.interaction.focusDragging=!0,this.state.focusMarker.style.cursor="grabbing";const e=this.state.focusMarker.getBoundingClientRect();this.interaction.focusDragOffsetX=t.clientX-(e.left+e.width/2),this.interaction.focusDragOffsetY=t.clientY-(e.top+e.height/2),t.preventDefault()}_createCropOverlay(){if(this.state.cropOverlay)return;const t=document.createElement("div");t.style.position="absolute",t.style.border=this.options.cropZone.style.border,t.style.backgroundColor=this.options.cropZone.style.backgroundColor,t.style.boxSizing="border-box",t.style.cursor="move",t.style.display="none",t.style.zIndex="998";const e=["tl","tm","tr","ml","mr","bl","bm","br"];for(const i of e){const e=document.createElement("div");switch(e.style.position="absolute",e.style.width=this.options.cropZone.handleStyle.width,e.style.height=this.options.cropZone.handleStyle.height,e.style.backgroundColor=this.options.cropZone.handleStyle.backgroundColor,e.style.border=this.options.cropZone.handleStyle.border,e.style.boxShadow=this.options.cropZone.handleStyle.boxShadow,e.style.boxSizing="border-box",e.dataset.handle=i,i){case"tl":e.style.top="-7px",e.style.left="-7px",e.style.cursor="nwse-resize";break;case"tm":e.style.top="-7px",e.style.left="50%",e.style.marginLeft="-7px",e.style.cursor="ns-resize";break;case"tr":e.style.top="-7px",e.style.right="-7px",e.style.cursor="nesw-resize";break;case"ml":e.style.top="50%",e.style.left="-7px",e.style.marginTop="-7px",e.style.cursor="ew-resize";break;case"mr":e.style.top="50%",e.style.right="-7px",e.style.marginTop="-7px",e.style.cursor="ew-resize";break;case"bl":e.style.bottom="-7px",e.style.left="-7px",e.style.cursor="nesw-resize";break;case"bm":e.style.bottom="-7px",e.style.left="50%",e.style.marginLeft="-7px",e.style.cursor="ns-resize";break;case"br":e.style.bottom="-7px",e.style.right="-7px",e.style.cursor="nwse-resize"}e.addEventListener("mousedown",(t=>this._handleCropHandleMouseDown(t,i))),t.appendChild(e)}t.addEventListener("mousedown",this._handleCropOverlayMouseDown.bind(this)),this.imageElement.parentNode.appendChild(t),this.state.cropOverlay=t}_handleCropHandleMouseDown(t,e){this.interaction.cropResizing=!0,this.interaction.activeHandle=e,this.interaction.startX=Number.parseInt(this.state.cropOverlay.style.left,10)||0,this.interaction.startY=Number.parseInt(this.state.cropOverlay.style.top,10)||0,this.interaction.startWidth=this.state.cropOverlay.offsetWidth,this.interaction.startHeight=this.state.cropOverlay.offsetHeight,this.interaction.startMouseX=t.clientX,this.interaction.startMouseY=t.clientY,t.preventDefault(),t.stopPropagation()}_handleCropOverlayMouseDown(t){t.target===this.state.cropOverlay&&(this.interaction.cropDragging=!0,this.state.cropOverlay.style.cursor="grabbing",this.interaction.startX=Number.parseInt(this.state.cropOverlay.style.left,10)||0,this.interaction.startY=Number.parseInt(this.state.cropOverlay.style.top,10)||0,this.interaction.startMouseX=t.clientX,this.interaction.startMouseY=t.clientY,t.preventDefault())}_setupEventListeners(){window.addEventListener("resize",this._updateScaling.bind(this)),this.imageElement.complete||this.imageElement.addEventListener("load",this._updateScaling.bind(this)),document.addEventListener("mouseup",this._handleMouseUp.bind(this)),document.addEventListener("mousemove",this._handleMouseMove.bind(this))}_handleMouseUp(){this.interaction.focusDragging&&(this.interaction.focusDragging=!1,this.state.focusMarker&&(this.state.focusMarker.style.cursor="move")),this.interaction.cropDragging&&(this.interaction.cropDragging=!1,this.state.cropOverlay&&(this.state.cropOverlay.style.cursor="move")),this.interaction.cropResizing=!1,this.interaction.activeHandle=null,document.body.style.cursor="default"}_handleMouseMove(t){this.interaction.focusDragging&&this.state.focusMarker&&this._handleFocusMarkerDrag(t),this.interaction.cropDragging&&this._handleCropOverlayDrag(t),this.interaction.cropResizing&&this._handleCropOverlayResize(t)}_handleFocusMarkerDrag(t){const e=this.imageElement.getBoundingClientRect(),i=t.clientX-e.left-this.interaction.focusDragOffsetX,s=t.clientY-e.top-this.interaction.focusDragOffsetY,o=this._toOriginalCoords(i,s);this.setFocusPoint(o.x,o.y)}_handleCropOverlayDrag(t){const e=t.clientX-this.interaction.startMouseX,i=t.clientY-this.interaction.startMouseY,s=this.interaction.startX+e,o=this.interaction.startY+i,a=this._toOriginalCoords(s,o),{width:r,height:n}=this.state.cropZone;this.setCropZone(a.x,a.y,r,n)}_handleCropOverlayResize(t){if(!this.interaction.activeHandle)return;const e=t.clientX-this.interaction.startMouseX,i=t.clientY-this.interaction.startMouseY;let s=this.interaction.startX,o=this.interaction.startY,a=this.interaction.startWidth,r=this.interaction.startHeight;this.interaction.activeHandle.includes("t")&&(o=this.interaction.startY+i,r=this.interaction.startHeight-i),this.interaction.activeHandle.includes("b")&&(r=this.interaction.startHeight+i),this.interaction.activeHandle.includes("l")&&(s=this.interaction.startX+e,a=this.interaction.startWidth-e),this.interaction.activeHandle.includes("r")&&(a=this.interaction.startWidth+e),a<10&&(this.interaction.activeHandle.includes("l")&&(s=this.interaction.startX+this.interaction.startWidth-10),a=10),r<10&&(this.interaction.activeHandle.includes("t")&&(o=this.interaction.startY+this.interaction.startHeight-10),r=10);const n=s/this.state.scaleX,h=o/this.state.scaleY,l=a/this.state.scaleX,c=r/this.state.scaleY;this.setCropZone(n,h,l,c)}_updateFocusMarkerPosition(){if(!this.state.focusMarker)return;const{x:t,y:e}=this.state.focusPoint,i=Math.max(0,Math.min(t,this.state.originalWidth)),s=Math.max(0,Math.min(e,this.state.originalHeight));t===i&&e===s||(this.state.focusPoint={x:i,y:s});const o=this._toScaledCoords(i,s);if(this.options.debug){const t=this.imageElement.parentNode,e=window.getComputedStyle(t),i=Number.parseFloat(e.paddingLeft),s=Number.parseFloat(e.paddingTop);console.log("[FocusMarker] scaled:",o,"paddingLeft:",i,"paddingTop:",s,"containerRect:",t.getBoundingClientRect())}let a=0,r=0;{const t=this.imageElement.parentNode,e=window.getComputedStyle(t);a=Number.parseFloat(e.paddingLeft),r=Number.parseFloat(e.paddingTop)}this.state.focusMarker.style.left=o.x+a-this.state.focusMarker.offsetWidth/2+"px",this.state.focusMarker.style.top=o.y+r-this.state.focusMarker.offsetHeight/2+"px",this.options.debug&&console.log("[FocusMarker] style.left:",this.state.focusMarker.style.left,"style.top:",this.state.focusMarker.style.top)}_updateCropOverlayPosition(){if(!this.state.cropOverlay)return;const{x:t,y:e,width:i,height:s}=this.state.cropZone,o=Math.max(0,Math.min(t,this.state.originalWidth-i)),a=Math.max(0,Math.min(e,this.state.originalHeight-s)),r=Math.max(10,Math.min(i,this.state.originalWidth-o)),n=Math.max(10,Math.min(s,this.state.originalHeight-a));t===o&&e===a&&i===r&&s===n||(this.state.cropZone={x:o,y:a,width:r,height:n});const h=this._toScaledCoords(o,a),l=r*this.state.scaleX,c=n*this.state.scaleY;if(this.options.debug){const t=this.imageElement.parentNode,e=window.getComputedStyle(t),i=Number.parseFloat(e.paddingLeft),s=Number.parseFloat(e.paddingTop);console.log("[CropOverlay] scaled:",h,"paddingLeft:",i,"paddingTop:",s,"containerRect:",t.getBoundingClientRect())}let d=0,p=0;{const t=this.imageElement.parentNode,e=window.getComputedStyle(t);d=Number.parseFloat(e.paddingLeft),p=Number.parseFloat(e.paddingTop)}this.state.cropOverlay.style.left=`${h.x+d}px`,this.state.cropOverlay.style.top=`${h.y+p}px`,this.state.cropOverlay.style.width=`${l}px`,this.state.cropOverlay.style.height=`${c}px`,this.options.debug&&console.log("[CropOverlay] style.left:",this.state.cropOverlay.style.left,"style.top:",this.state.cropOverlay.style.top)}toggleFocusPoint(t){return this.options.focusPoint.enabled?(void 0===t&&this.state.focusActive,t&&!this.state.focusActive?(this.state.focusMarker||this._createFocusMarker(),0===this.state.focusPoint.x&&0===this.state.focusPoint.y&&(this.state.focusPoint={x:this.state.originalWidth/2,y:this.state.originalHeight/2}),this._updateFocusMarkerPosition(),this.state.focusMarker.style.display="block",this.state.focusActive=!0):!t&&this.state.focusActive&&(this.state.focusMarker&&(this.state.focusMarker.style.display="none"),this.state.focusActive=!1),this._notifyChange(),this):this}toggleCropZone(t){if(!this.options.cropZone.enabled)return this;if(void 0===t&&this.state.cropActive,t&&!this.state.cropActive){if(this.state.cropOverlay||this._createCropOverlay(),0===this.state.cropZone.width||0===this.state.cropZone.height){const t=this.state.originalWidth/2,e=this.state.originalHeight/2,i=(this.state.originalWidth-t)/2,s=(this.state.originalHeight-e)/2;this.state.cropZone={x:i,y:s,width:t,height:e}}this._updateCropOverlayPosition(),this.state.cropOverlay.style.display="block",this.state.cropActive=!0}else!t&&this.state.cropActive&&(this.state.cropOverlay&&(this.state.cropOverlay.style.display="none"),this.state.cropActive=!1);return this._notifyChange(),this}setFocusPoint(t,e){const i=Math.max(0,Math.min(t,this.state.originalWidth)),s=Math.max(0,Math.min(e,this.state.originalHeight));return this.state.focusPoint={x:i,y:s},this.state.focusActive&&this.state.focusMarker&&this._updateFocusMarkerPosition(),this._notifyChange(),this}setCropZone(t,e,i,s){const o=Math.max(0,Math.min(t,this.state.originalWidth-i)),a=Math.max(0,Math.min(e,this.state.originalHeight-s)),r=Math.max(10,Math.min(i,this.state.originalWidth-o)),n=Math.max(10,Math.min(s,this.state.originalHeight-a));return this.state.cropZone={x:o,y:a,width:r,height:n},this.state.cropActive&&this.state.cropOverlay&&this._updateCropOverlayPosition(),this._notifyChange(),this}getFocusPoint(){return{...this.state.focusPoint}}getCropZone(){return{...this.state.cropZone}}getImageDimensions(){return{width:this.state.originalWidth,height:this.state.originalHeight}}_notifyChange(){"function"==typeof this.options.onChange&&this.options.onChange({focusPoint:this.getFocusPoint(),cropZone:this.getCropZone(),focusActive:this.state.focusActive,cropActive:this.state.cropActive})}destroy(){this.state.focusMarker?.parentNode&&this.state.focusMarker.parentNode.removeChild(this.state.focusMarker),this.state.cropOverlay?.parentNode&&this.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay),window.removeEventListener("resize",this._updateScaling.bind(this)),document.removeEventListener("mouseup",this._handleMouseUp.bind(this)),document.removeEventListener("mousemove",this._handleMouseMove.bind(this)),this.state=null,this.interaction=null,this.options=null,this.imageElement=null}}t.VisualImageTool=e,t.default=e,Object.defineProperty(t,"__esModule",{value:!0})}));
|
|
2
2
|
//# sourceMappingURL=visual-image-tool.umd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-image-tool.umd.js","sources":["../src/visual-image-tool.js"],"sourcesContent":["/**\n * ImageTool - Un outil léger pour définir des points focaux et zones de recadrage sur des images\n * @module visual-image-tool\n */\n\nclass VisualImageTool {\n /**\n * Crée une instance de l'outil d'image\n * @param {Object} options - Options de configuration\n * @param {HTMLElement|string} options.imageElement - Élément image ou sélecteur CSS\n * @param {Object} [options.focusPoint] - Configuration du point focal\n * @param {boolean} [options.focusPoint.enabled=true] - Activer la fonctionnalité de point focal\n * @param {Object} [options.focusPoint.style] - Styles personnalisés pour le marqueur de point focal\n * @param {Object} [options.cropZone] - Configuration de la zone de recadrage\n * @param {boolean} [options.cropZone.enabled=true] - Activer la fonctionnalité de zone de recadrage\n * @param {Object} [options.cropZone.style] - Styles personnalisés pour l'overlay de recadrage\n * @param {Function} [options.onChange] - Callback appelé lors des changements\n */\n constructor(options) {\n // Valider les options\n if (!options || !options.imageElement) {\n throw new Error('L\\'élément image est requis');\n }\n \n // Initialiser les propriétés\n this.imageElement = typeof options.imageElement === 'string' \n ? document.querySelector(options.imageElement) \n : options.imageElement;\n \n if (!this.imageElement || this.imageElement.tagName !== 'IMG') {\n throw new Error('Élément image invalide');\n }\n \n // Options par défaut\n this.options = {\n focusPoint: {\n enabled: true,\n style: {\n width: '30px',\n height: '30px',\n border: '3px solid white',\n boxShadow: '0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)',\n backgroundColor: 'rgba(255, 0, 0, 0.5)'\n },\n ...options.focusPoint\n },\n cropZone: {\n enabled: true,\n style: {\n border: '1px dashed #fff',\n backgroundColor: 'rgba(0, 0, 0, 0.4)'\n },\n handleStyle: {\n width: '14px',\n height: '14px',\n backgroundColor: 'white',\n border: '2px solid black',\n boxShadow: '0 0 3px rgba(0,0,0,0.5)'\n },\n ...options.cropZone\n },\n onChange: options.onChange || (() => {}),\n debug: options.debug || false\n };\n \n // État interne\n this.state = {\n focusMarker: null,\n cropOverlay: null,\n focusActive: false,\n cropActive: false,\n focusPoint: { x: 0, y: 0 },\n cropZone: { x: 0, y: 0, width: 0, height: 0 },\n originalWidth: 1,\n originalHeight: 1,\n displayWidth: 1,\n displayHeight: 1,\n scaleX: 1,\n scaleY: 1\n };\n \n // Variables pour le suivi des interactions\n this.interaction = {\n focusDragging: false,\n focusDragOffsetX: 0,\n focusDragOffsetY: 0,\n cropDragging: false,\n cropResizing: false,\n activeHandle: null,\n startX: 0,\n startY: 0,\n startWidth: 0,\n startHeight: 0,\n startMouseX: 0,\n startMouseY: 0\n };\n \n // Initialiser l'outil\n this._init();\n }\n \n /**\n * Initialise l'outil d'image\n * @private\n */\n _init() {\n // Préparer le conteneur parent\n this._prepareContainer();\n \n // Initialiser les dimensions\n this._updateScaling();\n \n // Créer les éléments d'interface si activés\n if (this.options.focusPoint.enabled) {\n this._createFocusMarker();\n }\n \n if (this.options.cropZone.enabled) {\n this._createCropOverlay();\n }\n \n // Ajouter les écouteurs d'événements\n this._setupEventListeners();\n }\n \n /**\n * Prépare le conteneur parent de l'image\n * @private\n */\n _prepareContainer() {\n // S'assurer que le parent est positionné\n if (this.imageElement.parentNode) {\n this.imageElement.parentNode.style.position = 'relative';\n }\n }\n \n /**\n * Met à jour les facteurs d'échelle\n * @private\n */\n _updateScaling() {\n this.state.originalWidth = this.imageElement.naturalWidth || 1;\n this.state.originalHeight = this.imageElement.naturalHeight || 1;\n this.state.displayWidth = this.imageElement.offsetWidth;\n this.state.displayHeight = this.imageElement.offsetHeight;\n this.state.scaleX = this.state.displayWidth / this.state.originalWidth;\n this.state.scaleY = this.state.displayHeight / this.state.originalHeight;\n \n // Repositionner les éléments si actifs\n if (this.state.focusActive) {\n this._updateFocusMarkerPosition();\n }\n \n if (this.state.cropActive) {\n this._updateCropOverlayPosition();\n }\n }\n \n /**\n * Convertit des coordonnées d'affichage en coordonnées originales\n * @private\n * @param {number} scaledX - Coordonnée X à l'échelle d'affichage\n * @param {number} scaledY - Coordonnée Y à l'échelle d'affichage\n * @returns {Object} Coordonnées originales\n */\n _toOriginalCoords(scaledX, scaledY) {\n return { \n x: scaledX / this.state.scaleX, \n y: scaledY / this.state.scaleY \n };\n }\n \n /**\n * Convertit des coordonnées originales en coordonnées d'affichage\n * @private\n * @param {number} originalX - Coordonnée X originale\n * @param {number} originalY - Coordonnée Y originale\n * @returns {Object} Coordonnées à l'échelle d'affichage\n */\n _toScaledCoords(originalX, originalY) {\n return { \n x: originalX * this.state.scaleX, \n y: originalY * this.state.scaleY \n };\n }\n \n /**\n * Crée le marqueur de point focal\n * @private\n */\n _createFocusMarker() {\n if (this.state.focusMarker) return;\n \n const marker = document.createElement('div');\n marker.style.position = 'absolute';\n marker.style.width = this.options.focusPoint.style.width;\n marker.style.height = this.options.focusPoint.style.height;\n marker.style.border = this.options.focusPoint.style.border;\n marker.style.boxShadow = this.options.focusPoint.style.boxShadow;\n marker.style.backgroundColor = this.options.focusPoint.style.backgroundColor;\n marker.style.cursor = 'move';\n marker.style.display = 'none';\n marker.style.zIndex = '999';\n marker.style.clipPath = 'polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)';\n \n this.imageElement.parentNode.appendChild(marker);\n this.state.focusMarker = marker;\n \n // Ajouter les écouteurs d'événements au marqueur\n marker.addEventListener('mousedown', this._handleFocusMarkerMouseDown.bind(this));\n }\n \n /**\n * Gère l'événement mousedown sur le marqueur de point focal\n * @private\n * @param {MouseEvent} e - Événement mousedown\n */\n _handleFocusMarkerMouseDown(e) {\n this.interaction.focusDragging = true;\n this.state.focusMarker.style.cursor = 'grabbing';\n \n // Calculer le décalage par rapport au centre du marqueur\n const rect = this.state.focusMarker.getBoundingClientRect();\n this.interaction.focusDragOffsetX = e.clientX - (rect.left + rect.width / 2);\n this.interaction.focusDragOffsetY = e.clientY - (rect.top + rect.height / 2);\n \n e.preventDefault();\n }\n \n /**\n * Crée l'overlay de zone de recadrage\n * @private\n */\n _createCropOverlay() {\n if (this.state.cropOverlay) return;\n \n const overlay = document.createElement('div');\n overlay.style.position = 'absolute';\n overlay.style.border = this.options.cropZone.style.border;\n overlay.style.backgroundColor = this.options.cropZone.style.backgroundColor;\n overlay.style.boxSizing = 'border-box';\n overlay.style.cursor = 'move';\n overlay.style.display = 'none';\n overlay.style.zIndex = '998';\n \n // Ajouter les poignées de redimensionnement\n const handles = ['tl', 'tm', 'tr', 'ml', 'mr', 'bl', 'bm', 'br'];\n handles.forEach(handleType => {\n const handle = document.createElement('div');\n handle.style.position = 'absolute';\n handle.style.width = this.options.cropZone.handleStyle.width;\n handle.style.height = this.options.cropZone.handleStyle.height;\n handle.style.backgroundColor = this.options.cropZone.handleStyle.backgroundColor;\n handle.style.border = this.options.cropZone.handleStyle.border;\n handle.style.boxShadow = this.options.cropZone.handleStyle.boxShadow;\n handle.style.boxSizing = 'border-box';\n handle.dataset.handle = handleType;\n \n // Positionner la poignée\n switch (handleType) {\n case 'tl': // Top-left\n handle.style.top = '-7px';\n handle.style.left = '-7px';\n handle.style.cursor = 'nwse-resize';\n break;\n case 'tm': // Top-middle\n handle.style.top = '-7px';\n handle.style.left = '50%';\n handle.style.marginLeft = '-7px';\n handle.style.cursor = 'ns-resize';\n break;\n case 'tr': // Top-right\n handle.style.top = '-7px';\n handle.style.right = '-7px';\n handle.style.cursor = 'nesw-resize';\n break;\n case 'ml': // Middle-left\n handle.style.top = '50%';\n handle.style.left = '-7px';\n handle.style.marginTop = '-7px';\n handle.style.cursor = 'ew-resize';\n break;\n case 'mr': // Middle-right\n handle.style.top = '50%';\n handle.style.right = '-7px';\n handle.style.marginTop = '-7px';\n handle.style.cursor = 'ew-resize';\n break;\n case 'bl': // Bottom-left\n handle.style.bottom = '-7px';\n handle.style.left = '-7px';\n handle.style.cursor = 'nesw-resize';\n break;\n case 'bm': // Bottom-middle\n handle.style.bottom = '-7px';\n handle.style.left = '50%';\n handle.style.marginLeft = '-7px';\n handle.style.cursor = 'ns-resize';\n break;\n case 'br': // Bottom-right\n handle.style.bottom = '-7px';\n handle.style.right = '-7px';\n handle.style.cursor = 'nwse-resize';\n break;\n }\n \n // Ajouter l'écouteur d'événement\n handle.addEventListener('mousedown', (e) => this._handleCropHandleMouseDown(e, handleType));\n \n overlay.appendChild(handle);\n });\n \n // Ajouter l'écouteur pour le déplacement de l'overlay\n overlay.addEventListener('mousedown', this._handleCropOverlayMouseDown.bind(this));\n \n this.imageElement.parentNode.appendChild(overlay);\n this.state.cropOverlay = overlay;\n }\n \n /**\n * Gère l'événement mousedown sur une poignée de redimensionnement\n * @private\n * @param {MouseEvent} e - Événement mousedown\n * @param {string} handleType - Type de poignée\n */\n _handleCropHandleMouseDown(e, handleType) {\n this.interaction.cropResizing = true;\n this.interaction.activeHandle = handleType;\n \n // Enregistrer les dimensions et position initiales\n this.interaction.startX = parseInt(this.state.cropOverlay.style.left, 10) || 0;\n this.interaction.startY = parseInt(this.state.cropOverlay.style.top, 10) || 0;\n this.interaction.startWidth = this.state.cropOverlay.offsetWidth;\n this.interaction.startHeight = this.state.cropOverlay.offsetHeight;\n this.interaction.startMouseX = e.clientX;\n this.interaction.startMouseY = e.clientY;\n \n e.preventDefault();\n e.stopPropagation();\n }\n \n /**\n * Gère l'événement mousedown sur l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousedown\n */\n _handleCropOverlayMouseDown(e) {\n // Ignorer si on clique sur une poignée\n if (e.target !== this.state.cropOverlay) return;\n \n this.interaction.cropDragging = true;\n this.state.cropOverlay.style.cursor = 'grabbing';\n \n // Enregistrer la position initiale\n this.interaction.startX = parseInt(this.state.cropOverlay.style.left, 10) || 0;\n this.interaction.startY = parseInt(this.state.cropOverlay.style.top, 10) || 0;\n this.interaction.startMouseX = e.clientX;\n this.interaction.startMouseY = e.clientY;\n \n e.preventDefault();\n }\n \n /**\n * Configure les écouteurs d'événements globaux\n * @private\n */\n _setupEventListeners() {\n // Écouteur pour le redimensionnement de la fenêtre\n window.addEventListener('resize', this._updateScaling.bind(this));\n \n // Écouteur pour le chargement de l'image\n if (!this.imageElement.complete) {\n this.imageElement.addEventListener('load', this._updateScaling.bind(this));\n }\n \n // Écouteurs pour les interactions de souris\n document.addEventListener('mouseup', this._handleMouseUp.bind(this));\n document.addEventListener('mousemove', this._handleMouseMove.bind(this));\n }\n \n /**\n * Gère l'événement mouseup global\n * @private\n */\n _handleMouseUp() {\n if (this.interaction.focusDragging) {\n this.interaction.focusDragging = false;\n if (this.state.focusMarker) this.state.focusMarker.style.cursor = 'move';\n }\n \n if (this.interaction.cropDragging) {\n this.interaction.cropDragging = false;\n if (this.state.cropOverlay) this.state.cropOverlay.style.cursor = 'move';\n }\n \n this.interaction.cropResizing = false;\n this.interaction.activeHandle = null;\n document.body.style.cursor = 'default';\n }\n \n /**\n * Gère l'événement mousemove global\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleMouseMove(e) {\n // Gestion du déplacement du point focal\n if (this.interaction.focusDragging && this.state.focusMarker) {\n this._handleFocusMarkerDrag(e);\n }\n \n // Gestion du déplacement de la zone de recadrage\n if (this.interaction.cropDragging) {\n this._handleCropOverlayDrag(e);\n }\n \n // Gestion du redimensionnement de la zone de recadrage\n if (this.interaction.cropResizing) {\n this._handleCropOverlayResize(e);\n }\n }\n \n /**\n * Gère le déplacement du marqueur de point focal\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleFocusMarkerDrag(e) {\n const imageRect = this.imageElement.getBoundingClientRect();\n \n // Calculer la position cible relative à l'image\n const targetScaledX = e.clientX - imageRect.left - this.interaction.focusDragOffsetX;\n const targetScaledY = e.clientY - imageRect.top - this.interaction.focusDragOffsetY;\n \n // Convertir en coordonnées originales\n const original = this._toOriginalCoords(targetScaledX, targetScaledY);\n \n // Mettre à jour le point focal\n this.setFocusPoint(original.x, original.y);\n }\n \n /**\n * Gère le déplacement de l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleCropOverlayDrag(e) {\n const deltaX = e.clientX - this.interaction.startMouseX;\n const deltaY = e.clientY - this.interaction.startMouseY;\n \n // Calculer la nouvelle position en pixels d'affichage\n let newX = this.interaction.startX + deltaX;\n let newY = this.interaction.startY + deltaY;\n \n // Convertir en coordonnées originales\n const original = this._toOriginalCoords(newX, newY);\n \n // Obtenir les dimensions actuelles en coordonnées originales\n const { width, height } = this.state.cropZone;\n \n // Mettre à jour la zone de recadrage\n this.setCropZone(original.x, original.y, width, height);\n }\n \n /**\n * Gère le redimensionnement de l'overlay de recadrage\n * @private\n * @param {MouseEvent} e - Événement mousemove\n */\n _handleCropOverlayResize(e) {\n if (!this.interaction.activeHandle) return;\n \n const deltaX = e.clientX - this.interaction.startMouseX;\n const deltaY = e.clientY - this.interaction.startMouseY;\n \n let newX = this.interaction.startX;\n let newY = this.interaction.startY;\n let newWidth = this.interaction.startWidth;\n let newHeight = this.interaction.startHeight;\n \n // Ajuster en fonction de la poignée active\n if (this.interaction.activeHandle.includes('t')) { // Top\n newY = this.interaction.startY + deltaY;\n newHeight = this.interaction.startHeight - deltaY;\n }\n if (this.interaction.activeHandle.includes('b')) { // Bottom\n newHeight = this.interaction.startHeight + deltaY;\n }\n if (this.interaction.activeHandle.includes('l')) { // Left\n newX = this.interaction.startX + deltaX;\n newWidth = this.interaction.startWidth - deltaX;\n }\n if (this.interaction.activeHandle.includes('r')) { // Right\n newWidth = this.interaction.startWidth + deltaX;\n }\n \n // Empêcher les dimensions négatives\n if (newWidth < 10) {\n if (this.interaction.activeHandle.includes('l')) {\n newX = this.interaction.startX + this.interaction.startWidth - 10;\n }\n newWidth = 10;\n }\n if (newHeight < 10) {\n if (this.interaction.activeHandle.includes('t')) {\n newY = this.interaction.startY + this.interaction.startHeight - 10;\n }\n newHeight = 10;\n }\n \n // Convertir les coordonnées d'affichage en coordonnées originales\n const originalX = newX / this.state.scaleX;\n const originalY = newY / this.state.scaleY;\n const originalWidth = newWidth / this.state.scaleX;\n const originalHeight = newHeight / this.state.scaleY;\n \n // Mettre à jour la zone de recadrage\n this.setCropZone(originalX, originalY, originalWidth, originalHeight);\n }\n \n /**\n * Met à jour la position du marqueur de point focal\n * @private\n */\n _updateFocusMarkerPosition() {\n if (!this.state.focusMarker) return;\n \n const { x, y } = this.state.focusPoint;\n \n // Limiter les coordonnées aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n \n // Mettre à jour l'état si les coordonnées ont été limitées\n if (x !== clampedX || y !== clampedY) {\n this.state.focusPoint = { x: clampedX, y: clampedY };\n }\n \n const scaled = this._toScaledCoords(clampedX, clampedY);\n\n // LOGGING: Validate padding offset\n if (this.options.debug) {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n const paddingTop = parseFloat(computedStyle.paddingTop);\n console.log('[FocusMarker] scaled:', scaled, 'paddingLeft:', paddingLeft, 'paddingTop:', paddingTop, 'containerRect:', container.getBoundingClientRect());\n }\n\n // Ajuster pour centrer le marqueur\n // Adjust for container padding (use unique variable names)\n let focusPaddingLeft = 0, focusPaddingTop = 0;\n {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n focusPaddingLeft = parseFloat(computedStyle.paddingLeft);\n focusPaddingTop = parseFloat(computedStyle.paddingTop);\n }\n\n this.state.focusMarker.style.left = (scaled.x + focusPaddingLeft - this.state.focusMarker.offsetWidth / 2) + 'px';\n this.state.focusMarker.style.top = (scaled.y + focusPaddingTop - this.state.focusMarker.offsetHeight / 2) + 'px';\n if (this.options.debug) {\n console.log('[FocusMarker] style.left:', this.state.focusMarker.style.left, 'style.top:', this.state.focusMarker.style.top);\n }\n }\n \n /**\n * Met à jour la position et les dimensions de l'overlay de recadrage\n * @private\n */\n _updateCropOverlayPosition() {\n if (!this.state.cropOverlay) return;\n \n const { x, y, width, height } = this.state.cropZone;\n \n // Limiter aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight - height));\n const clampedWidth = Math.max(10, Math.min(width, this.state.originalWidth - clampedX));\n const clampedHeight = Math.max(10, Math.min(height, this.state.originalHeight - clampedY));\n \n // Mettre à jour l'état si les valeurs ont été limitées\n if (x !== clampedX || y !== clampedY || width !== clampedWidth || height !== clampedHeight) {\n this.state.cropZone = { x: clampedX, y: clampedY, width: clampedWidth, height: clampedHeight };\n }\n \n // Convertir en coordonnées d'affichage\n const scaled = this._toScaledCoords(clampedX, clampedY);\n const scaledWidth = clampedWidth * this.state.scaleX;\n const scaledHeight = clampedHeight * this.state.scaleY;\n\n // LOGGING: Validate padding offset\n if (this.options.debug) {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n const paddingTop = parseFloat(computedStyle.paddingTop);\n console.log('[CropOverlay] scaled:', scaled, 'paddingLeft:', paddingLeft, 'paddingTop:', paddingTop, 'containerRect:', container.getBoundingClientRect());\n }\n\n // Mettre à jour l'overlay\n // Adjust for container padding (use unique variable names)\n let cropPaddingLeft = 0, cropPaddingTop = 0;\n {\n const container = this.imageElement.parentNode;\n const computedStyle = window.getComputedStyle(container);\n cropPaddingLeft = parseFloat(computedStyle.paddingLeft);\n cropPaddingTop = parseFloat(computedStyle.paddingTop);\n }\n\n this.state.cropOverlay.style.left = (scaled.x + cropPaddingLeft) + 'px';\n this.state.cropOverlay.style.top = (scaled.y + cropPaddingTop) + 'px';\n this.state.cropOverlay.style.width = scaledWidth + 'px';\n this.state.cropOverlay.style.height = scaledHeight + 'px';\n if (this.options.debug) {\n console.log('[CropOverlay] style.left:', this.state.cropOverlay.style.left, 'style.top:', this.state.cropOverlay.style.top);\n }\n }\n \n /**\n * Active ou désactive le point focal\n * @public\n * @param {boolean} active - État d'activation\n * @returns {ImageTool} Instance pour chaînage\n */\n toggleFocusPoint(active) {\n if (!this.options.focusPoint.enabled) return this;\n \n if (active === undefined) {\n active = !this.state.focusActive;\n }\n \n if (active && !this.state.focusActive) {\n // Activer le point focal\n if (!this.state.focusMarker) {\n this._createFocusMarker();\n }\n \n // Positionner au centre de l'image par défaut si pas déjà défini\n if (this.state.focusPoint.x === 0 && this.state.focusPoint.y === 0) {\n this.state.focusPoint = {\n x: this.state.originalWidth / 2,\n y: this.state.originalHeight / 2\n };\n }\n \n this._updateFocusMarkerPosition();\n this.state.focusMarker.style.display = 'block';\n this.state.focusActive = true;\n } else if (!active && this.state.focusActive) {\n // Désactiver le point focal\n if (this.state.focusMarker) {\n this.state.focusMarker.style.display = 'none';\n }\n this.state.focusActive = false;\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Active ou désactive la zone de recadrage\n * @public\n * @param {boolean} active - État d'activation\n * @returns {ImageTool} Instance pour chaînage\n */\n toggleCropZone(active) {\n if (!this.options.cropZone.enabled) return this;\n \n if (active === undefined) {\n active = !this.state.cropActive;\n }\n \n if (active && !this.state.cropActive) {\n // Activer la zone de recadrage\n if (!this.state.cropOverlay) {\n this._createCropOverlay();\n }\n \n // Définir une zone par défaut si pas déjà définie\n if (this.state.cropZone.width === 0 || this.state.cropZone.height === 0) {\n const defaultWidth = this.state.originalWidth / 2;\n const defaultHeight = this.state.originalHeight / 2;\n const defaultX = (this.state.originalWidth - defaultWidth) / 2;\n const defaultY = (this.state.originalHeight - defaultHeight) / 2;\n \n this.state.cropZone = {\n x: defaultX,\n y: defaultY,\n width: defaultWidth,\n height: defaultHeight\n };\n }\n \n this._updateCropOverlayPosition();\n this.state.cropOverlay.style.display = 'block';\n this.state.cropActive = true;\n } else if (!active && this.state.cropActive) {\n // Désactiver la zone de recadrage\n if (this.state.cropOverlay) {\n this.state.cropOverlay.style.display = 'none';\n }\n this.state.cropActive = false;\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Définit la position du point focal\n * @public\n * @param {number} x - Coordonnée X en pixels originaux\n * @param {number} y - Coordonnée Y en pixels originaux\n * @returns {ImageTool} Instance pour chaînage\n */\n setFocusPoint(x, y) {\n // Limiter les coordonnées aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n \n this.state.focusPoint = { x: clampedX, y: clampedY };\n \n if (this.state.focusActive && this.state.focusMarker) {\n this._updateFocusMarkerPosition();\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Définit la position et les dimensions de la zone de recadrage\n * @public\n * @param {number} x - Coordonnée X en pixels originaux\n * @param {number} y - Coordonnée Y en pixels originaux\n * @param {number} width - Largeur en pixels originaux\n * @param {number} height - Hauteur en pixels originaux\n * @returns {ImageTool} Instance pour chaînage\n */\n setCropZone(x, y, width, height) {\n // Limiter aux dimensions de l'image\n const clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n const clampedY = Math.max(0, Math.min(y, this.state.originalHeight - height));\n const clampedWidth = Math.max(10, Math.min(width, this.state.originalWidth - clampedX));\n const clampedHeight = Math.max(10, Math.min(height, this.state.originalHeight - clampedY));\n \n this.state.cropZone = {\n x: clampedX,\n y: clampedY,\n width: clampedWidth,\n height: clampedHeight\n };\n \n if (this.state.cropActive && this.state.cropOverlay) {\n this._updateCropOverlayPosition();\n }\n \n // Notifier le changement\n this._notifyChange();\n \n return this;\n }\n \n /**\n * Obtient la position actuelle du point focal\n * @public\n * @returns {Object} Coordonnées du point focal {x, y}\n */\n getFocusPoint() {\n return { ...this.state.focusPoint };\n }\n \n /**\n * Obtient la position et les dimensions actuelles de la zone de recadrage\n * @public\n * @returns {Object} Zone de recadrage {x, y, width, height}\n */\n getCropZone() {\n return { ...this.state.cropZone };\n }\n \n /**\n * Obtient les dimensions originales de l'image\n * @public\n * @returns {Object} Dimensions {width, height}\n */\n getImageDimensions() {\n return {\n width: this.state.originalWidth,\n height: this.state.originalHeight\n };\n }\n \n /**\n * Notifie les changements via le callback\n * @private\n */\n _notifyChange() {\n if (typeof this.options.onChange === 'function') {\n this.options.onChange({\n focusPoint: this.getFocusPoint(),\n cropZone: this.getCropZone(),\n focusActive: this.state.focusActive,\n cropActive: this.state.cropActive\n });\n }\n }\n \n /**\n * Détruit l'instance et nettoie les ressources\n * @public\n */\n destroy() {\n // Supprimer les éléments DOM\n if (this.state.focusMarker && this.state.focusMarker.parentNode) {\n this.state.focusMarker.parentNode.removeChild(this.state.focusMarker);\n }\n \n if (this.state.cropOverlay && this.state.cropOverlay.parentNode) {\n this.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay);\n }\n \n // Supprimer les écouteurs d'événements\n window.removeEventListener('resize', this._updateScaling.bind(this));\n document.removeEventListener('mouseup', this._handleMouseUp.bind(this));\n document.removeEventListener('mousemove', this._handleMouseMove.bind(this));\n \n // Réinitialiser l'état\n this.state = null;\n this.interaction = null;\n this.options = null;\n this.imageElement = null;\n }\n }\n \n // Exporter la classe\n export default VisualImageTool;\n "],"names":["VisualImageTool","constructor","options","imageElement","Error","this","document","querySelector","tagName","focusPoint","enabled","style","width","height","border","boxShadow","backgroundColor","cropZone","handleStyle","onChange","debug","state","focusMarker","cropOverlay","focusActive","cropActive","x","y","originalWidth","originalHeight","displayWidth","displayHeight","scaleX","scaleY","interaction","focusDragging","focusDragOffsetX","focusDragOffsetY","cropDragging","cropResizing","activeHandle","startX","startY","startWidth","startHeight","startMouseX","startMouseY","_init","_prepareContainer","_updateScaling","_createFocusMarker","_createCropOverlay","_setupEventListeners","parentNode","position","naturalWidth","naturalHeight","offsetWidth","offsetHeight","_updateFocusMarkerPosition","_updateCropOverlayPosition","_toOriginalCoords","scaledX","scaledY","_toScaledCoords","originalX","originalY","marker","createElement","cursor","display","zIndex","clipPath","appendChild","addEventListener","_handleFocusMarkerMouseDown","bind","e","rect","getBoundingClientRect","clientX","left","clientY","top","preventDefault","overlay","boxSizing","forEach","handleType","handle","dataset","marginLeft","right","marginTop","bottom","_handleCropHandleMouseDown","_handleCropOverlayMouseDown","parseInt","stopPropagation","target","window","complete","_handleMouseUp","_handleMouseMove","body","_handleFocusMarkerDrag","_handleCropOverlayDrag","_handleCropOverlayResize","imageRect","targetScaledX","targetScaledY","original","setFocusPoint","deltaX","deltaY","newX","newY","setCropZone","newWidth","newHeight","includes","clampedX","Math","max","min","clampedY","scaled","container","computedStyle","getComputedStyle","paddingLeft","parseFloat","paddingTop","console","log","focusPaddingLeft","focusPaddingTop","clampedWidth","clampedHeight","scaledWidth","scaledHeight","cropPaddingLeft","cropPaddingTop","toggleFocusPoint","active","undefined","_notifyChange","toggleCropZone","defaultWidth","defaultHeight","defaultX","defaultY","getFocusPoint","getCropZone","getImageDimensions","destroy","removeChild","removeEventListener"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"visual-image-tool.umd.js","sources":["../src/visual-image-tool.js"],"sourcesContent":["/**\n * ImageTool - Un outil léger pour définir des points focaux et zones de recadrage sur des images\n * @module visual-image-tool\n */\n\nclass VisualImageTool {\n\t/**\n\t * Crée une instance de l'outil d'image\n\t * @param {Object} options - Options de configuration\n\t * @param {HTMLElement|string} options.imageElement - Élément image ou sélecteur CSS\n\t * @param {Object} [options.focusPoint] - Configuration du point focal\n\t * @param {boolean} [options.focusPoint.enabled=true] - Activer la fonctionnalité de point focal\n\t * @param {Object} [options.focusPoint.style] - Styles personnalisés pour le marqueur de point focal\n\t * @param {Object} [options.cropZone] - Configuration de la zone de recadrage\n\t * @param {boolean} [options.cropZone.enabled=true] - Activer la fonctionnalité de zone de recadrage\n\t * @param {Object} [options.cropZone.style] - Styles personnalisés pour l'overlay de recadrage\n\t * @param {Function} [options.onChange] - Callback appelé lors des changements\n\t */\n\tconstructor(options) {\n\t\t// Valider les options\n\t\tif (!options || !options.imageElement) {\n\t\t\tthrow new Error(\"L'élément image est requis\");\n\t\t}\n\n\t\t// Initialiser les propriétés\n\t\tthis.imageElement =\n\t\t\ttypeof options.imageElement === \"string\"\n\t\t\t\t? document.querySelector(options.imageElement)\n\t\t\t\t: options.imageElement;\n\n\t\tif (!this.imageElement || this.imageElement.tagName !== \"IMG\") {\n\t\t\tthrow new Error(\"Élément image invalide\");\n\t\t}\n\n\t\t// Options par défaut\n\t\tthis.options = {\n\t\t\tfocusPoint: {\n\t\t\t\tenabled: true,\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: \"30px\",\n\t\t\t\t\theight: \"30px\",\n\t\t\t\t\tborder: \"3px solid white\",\n\t\t\t\t\tboxShadow: \"0 0 0 2px black, 0 0 5px rgba(0,0,0,0.5)\",\n\t\t\t\t\tbackgroundColor: \"rgba(255, 0, 0, 0.5)\",\n\t\t\t\t},\n\t\t\t\t...options.focusPoint,\n\t\t\t},\n\t\t\tcropZone: {\n\t\t\t\tenabled: true,\n\t\t\t\tstyle: {\n\t\t\t\t\tborder: \"1px dashed #fff\",\n\t\t\t\t\tbackgroundColor: \"rgba(0, 0, 0, 0.4)\",\n\t\t\t\t},\n\t\t\t\thandleStyle: {\n\t\t\t\t\twidth: \"14px\",\n\t\t\t\t\theight: \"14px\",\n\t\t\t\t\tbackgroundColor: \"white\",\n\t\t\t\t\tborder: \"2px solid black\",\n\t\t\t\t\tboxShadow: \"0 0 3px rgba(0,0,0,0.5)\",\n\t\t\t\t},\n\t\t\t\t...options.cropZone,\n\t\t\t},\n\t\t\tonChange: options.onChange || (() => {}),\n\t\t\tdebug: options.debug || false,\n\t\t};\n\n\t\t// État interne\n\t\tthis.state = {\n\t\t\tfocusMarker: null,\n\t\t\tcropOverlay: null,\n\t\t\tfocusActive: false,\n\t\t\tcropActive: false,\n\t\t\tfocusPoint: { x: 0, y: 0 },\n\t\t\tcropZone: { x: 0, y: 0, width: 0, height: 0 },\n\t\t\toriginalWidth: 1,\n\t\t\toriginalHeight: 1,\n\t\t\tdisplayWidth: 1,\n\t\t\tdisplayHeight: 1,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t};\n\n\t\t// Variables pour le suivi des interactions\n\t\tthis.interaction = {\n\t\t\tfocusDragging: false,\n\t\t\tfocusDragOffsetX: 0,\n\t\t\tfocusDragOffsetY: 0,\n\t\t\tcropDragging: false,\n\t\t\tcropResizing: false,\n\t\t\tactiveHandle: null,\n\t\t\tstartX: 0,\n\t\t\tstartY: 0,\n\t\t\tstartWidth: 0,\n\t\t\tstartHeight: 0,\n\t\t\tstartMouseX: 0,\n\t\t\tstartMouseY: 0,\n\t\t};\n\n\t\t// Initialiser l'outil\n\t\tthis._init();\n\t}\n\n\t/**\n\t * Initialise l'outil d'image\n\t * @private\n\t */\n\t_init() {\n\t\t// Préparer le conteneur parent\n\t\tthis._prepareContainer();\n\n\t\t// Initialiser les dimensions\n\t\tthis._updateScaling();\n\n\t\t// Créer les éléments d'interface si activés\n\t\tif (this.options.focusPoint.enabled) {\n\t\t\tthis._createFocusMarker();\n\t\t}\n\n\t\tif (this.options.cropZone.enabled) {\n\t\t\tthis._createCropOverlay();\n\t\t}\n\n\t\t// Ajouter les écouteurs d'événements\n\t\tthis._setupEventListeners();\n\t}\n\n\t/**\n\t * Prépare le conteneur parent de l'image\n\t * @private\n\t */\n\t_prepareContainer() {\n\t\t// S'assurer que le parent est positionné\n\t\tif (this.imageElement.parentNode) {\n\t\t\tthis.imageElement.parentNode.style.position = \"relative\";\n\t\t}\n\t}\n\n\t/**\n\t * Met à jour les facteurs d'échelle\n\t * @private\n\t */\n\t_updateScaling() {\n\t\tthis.state.originalWidth = this.imageElement.naturalWidth || 1;\n\t\tthis.state.originalHeight = this.imageElement.naturalHeight || 1;\n\t\tthis.state.displayWidth = this.imageElement.offsetWidth;\n\t\tthis.state.displayHeight = this.imageElement.offsetHeight;\n\t\tthis.state.scaleX = this.state.displayWidth / this.state.originalWidth;\n\t\tthis.state.scaleY = this.state.displayHeight / this.state.originalHeight;\n\n\t\t// Repositionner les éléments si actifs\n\t\tif (this.state.focusActive) {\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t}\n\n\t\tif (this.state.cropActive) {\n\t\t\tthis._updateCropOverlayPosition();\n\t\t}\n\t}\n\n\t/**\n\t * Convertit des coordonnées d'affichage en coordonnées originales\n\t * @private\n\t * @param {number} scaledX - Coordonnée X à l'échelle d'affichage\n\t * @param {number} scaledY - Coordonnée Y à l'échelle d'affichage\n\t * @returns {Object} Coordonnées originales\n\t */\n\t_toOriginalCoords(scaledX, scaledY) {\n\t\treturn {\n\t\t\tx: scaledX / this.state.scaleX,\n\t\t\ty: scaledY / this.state.scaleY,\n\t\t};\n\t}\n\n\t/**\n\t * Convertit des coordonnées originales en coordonnées d'affichage\n\t * @private\n\t * @param {number} originalX - Coordonnée X originale\n\t * @param {number} originalY - Coordonnée Y originale\n\t * @returns {Object} Coordonnées à l'échelle d'affichage\n\t */\n\t_toScaledCoords(originalX, originalY) {\n\t\treturn {\n\t\t\tx: originalX * this.state.scaleX,\n\t\t\ty: originalY * this.state.scaleY,\n\t\t};\n\t}\n\n\t/**\n\t * Crée le marqueur de point focal\n\t * @private\n\t */\n\t_createFocusMarker() {\n\t\tif (this.state.focusMarker) return;\n\n\t\tconst marker = document.createElement(\"div\");\n\t\tmarker.style.position = \"absolute\";\n\t\tmarker.style.width = this.options.focusPoint.style.width;\n\t\tmarker.style.height = this.options.focusPoint.style.height;\n\t\tmarker.style.border = this.options.focusPoint.style.border;\n\t\tmarker.style.boxShadow = this.options.focusPoint.style.boxShadow;\n\t\tmarker.style.backgroundColor =\n\t\t\tthis.options.focusPoint.style.backgroundColor;\n\t\tmarker.style.cursor = \"move\";\n\t\tmarker.style.display = \"none\";\n\t\tmarker.style.zIndex = \"999\";\n\t\tmarker.style.clipPath =\n\t\t\t\"polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%)\";\n\n\t\tthis.imageElement.parentNode.appendChild(marker);\n\t\tthis.state.focusMarker = marker;\n\n\t\t// Ajouter les écouteurs d'événements au marqueur\n\t\tmarker.addEventListener(\n\t\t\t\"mousedown\",\n\t\t\tthis._handleFocusMarkerMouseDown.bind(this),\n\t\t);\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur le marqueur de point focal\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t */\n\t_handleFocusMarkerMouseDown(e) {\n\t\tthis.interaction.focusDragging = true;\n\t\tthis.state.focusMarker.style.cursor = \"grabbing\";\n\n\t\t// Calculer le décalage par rapport au centre du marqueur\n\t\tconst rect = this.state.focusMarker.getBoundingClientRect();\n\t\tthis.interaction.focusDragOffsetX =\n\t\t\te.clientX - (rect.left + rect.width / 2);\n\t\tthis.interaction.focusDragOffsetY =\n\t\t\te.clientY - (rect.top + rect.height / 2);\n\n\t\te.preventDefault();\n\t}\n\n\t/**\n\t * Crée l'overlay de zone de recadrage\n\t * @private\n\t */\n\t_createCropOverlay() {\n\t\tif (this.state.cropOverlay) return;\n\n\t\tconst overlay = document.createElement(\"div\");\n\t\toverlay.style.position = \"absolute\";\n\t\toverlay.style.border = this.options.cropZone.style.border;\n\t\toverlay.style.backgroundColor = this.options.cropZone.style.backgroundColor;\n\t\toverlay.style.boxSizing = \"border-box\";\n\t\toverlay.style.cursor = \"move\";\n\t\toverlay.style.display = \"none\";\n\t\toverlay.style.zIndex = \"998\";\n\n\t\t// Ajouter les poignées de redimensionnement\n\t\tconst handles = [\"tl\", \"tm\", \"tr\", \"ml\", \"mr\", \"bl\", \"bm\", \"br\"];\n\t\tfor (const handleType of handles) {\n\t\t\tconst handle = document.createElement(\"div\");\n\t\t\thandle.style.position = \"absolute\";\n\t\t\thandle.style.width = this.options.cropZone.handleStyle.width;\n\t\t\thandle.style.height = this.options.cropZone.handleStyle.height;\n\t\t\thandle.style.backgroundColor =\n\t\t\t\tthis.options.cropZone.handleStyle.backgroundColor;\n\t\t\thandle.style.border = this.options.cropZone.handleStyle.border;\n\t\t\thandle.style.boxShadow = this.options.cropZone.handleStyle.boxShadow;\n\t\t\thandle.style.boxSizing = \"border-box\";\n\t\t\thandle.dataset.handle = handleType;\n\n\t\t\t// Positionner la poignée\n\t\t\tswitch (handleType) {\n\t\t\t\tcase \"tl\": // Top-left\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nwse-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tm\": // Top-middle\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.left = \"50%\";\n\t\t\t\t\thandle.style.marginLeft = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ns-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tr\": // Top-right\n\t\t\t\t\thandle.style.top = \"-7px\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nesw-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ml\": // Middle-left\n\t\t\t\t\thandle.style.top = \"50%\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.marginTop = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ew-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"mr\": // Middle-right\n\t\t\t\t\thandle.style.top = \"50%\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.marginTop = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ew-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"bl\": // Bottom-left\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.left = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nesw-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"bm\": // Bottom-middle\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.left = \"50%\";\n\t\t\t\t\thandle.style.marginLeft = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"ns-resize\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"br\": // Bottom-right\n\t\t\t\t\thandle.style.bottom = \"-7px\";\n\t\t\t\t\thandle.style.right = \"-7px\";\n\t\t\t\t\thandle.style.cursor = \"nwse-resize\";\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Ajouter l'écouteur d'événement\n\t\t\thandle.addEventListener(\"mousedown\", (e) =>\n\t\t\t\tthis._handleCropHandleMouseDown(e, handleType),\n\t\t\t);\n\n\t\t\toverlay.appendChild(handle);\n\t\t}\n\n\t\t// Ajouter l'écouteur pour le déplacement de l'overlay\n\t\toverlay.addEventListener(\n\t\t\t\"mousedown\",\n\t\t\tthis._handleCropOverlayMouseDown.bind(this),\n\t\t);\n\n\t\tthis.imageElement.parentNode.appendChild(overlay);\n\t\tthis.state.cropOverlay = overlay;\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur une poignée de redimensionnement\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t * @param {string} handleType - Type de poignée\n\t */\n\t_handleCropHandleMouseDown(e, handleType) {\n\t\tthis.interaction.cropResizing = true;\n\t\tthis.interaction.activeHandle = handleType;\n\n\t\t// Enregistrer les dimensions et position initiales\n\t\tthis.interaction.startX =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.left, 10) || 0;\n\t\tthis.interaction.startY =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.top, 10) || 0;\n\t\tthis.interaction.startWidth = this.state.cropOverlay.offsetWidth;\n\t\tthis.interaction.startHeight = this.state.cropOverlay.offsetHeight;\n\t\tthis.interaction.startMouseX = e.clientX;\n\t\tthis.interaction.startMouseY = e.clientY;\n\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t}\n\n\t/**\n\t * Gère l'événement mousedown sur l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousedown\n\t */\n\t_handleCropOverlayMouseDown(e) {\n\t\t// Ignorer si on clique sur une poignée\n\t\tif (e.target !== this.state.cropOverlay) return;\n\n\t\tthis.interaction.cropDragging = true;\n\t\tthis.state.cropOverlay.style.cursor = \"grabbing\";\n\n\t\t// Enregistrer la position initiale\n\t\tthis.interaction.startX =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.left, 10) || 0;\n\t\tthis.interaction.startY =\n\t\t\tNumber.parseInt(this.state.cropOverlay.style.top, 10) || 0;\n\t\tthis.interaction.startMouseX = e.clientX;\n\t\tthis.interaction.startMouseY = e.clientY;\n\n\t\te.preventDefault();\n\t}\n\n\t/**\n\t * Configure les écouteurs d'événements globaux\n\t * @private\n\t */\n\t_setupEventListeners() {\n\t\t// Écouteur pour le redimensionnement de la fenêtre\n\t\twindow.addEventListener(\"resize\", this._updateScaling.bind(this));\n\n\t\t// Écouteur pour le chargement de l'image\n\t\tif (!this.imageElement.complete) {\n\t\t\tthis.imageElement.addEventListener(\n\t\t\t\t\"load\",\n\t\t\t\tthis._updateScaling.bind(this),\n\t\t\t);\n\t\t}\n\n\t\t// Écouteurs pour les interactions de souris\n\t\tdocument.addEventListener(\"mouseup\", this._handleMouseUp.bind(this));\n\t\tdocument.addEventListener(\"mousemove\", this._handleMouseMove.bind(this));\n\t}\n\n\t/**\n\t * Gère l'événement mouseup global\n\t * @private\n\t */\n\t_handleMouseUp() {\n\t\tif (this.interaction.focusDragging) {\n\t\t\tthis.interaction.focusDragging = false;\n\t\t\tif (this.state.focusMarker) this.state.focusMarker.style.cursor = \"move\";\n\t\t}\n\n\t\tif (this.interaction.cropDragging) {\n\t\t\tthis.interaction.cropDragging = false;\n\t\t\tif (this.state.cropOverlay) this.state.cropOverlay.style.cursor = \"move\";\n\t\t}\n\n\t\tthis.interaction.cropResizing = false;\n\t\tthis.interaction.activeHandle = null;\n\t\tdocument.body.style.cursor = \"default\";\n\t}\n\n\t/**\n\t * Gère l'événement mousemove global\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleMouseMove(e) {\n\t\t// Gestion du déplacement du point focal\n\t\tif (this.interaction.focusDragging && this.state.focusMarker) {\n\t\t\tthis._handleFocusMarkerDrag(e);\n\t\t}\n\n\t\t// Gestion du déplacement de la zone de recadrage\n\t\tif (this.interaction.cropDragging) {\n\t\t\tthis._handleCropOverlayDrag(e);\n\t\t}\n\n\t\t// Gestion du redimensionnement de la zone de recadrage\n\t\tif (this.interaction.cropResizing) {\n\t\t\tthis._handleCropOverlayResize(e);\n\t\t}\n\t}\n\n\t/**\n\t * Gère le déplacement du marqueur de point focal\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleFocusMarkerDrag(e) {\n\t\tconst imageRect = this.imageElement.getBoundingClientRect();\n\n\t\t// Calculer la position cible relative à l'image\n\t\tconst targetScaledX =\n\t\t\te.clientX - imageRect.left - this.interaction.focusDragOffsetX;\n\t\tconst targetScaledY =\n\t\t\te.clientY - imageRect.top - this.interaction.focusDragOffsetY;\n\n\t\t// Convertir en coordonnées originales\n\t\tconst original = this._toOriginalCoords(targetScaledX, targetScaledY);\n\n\t\t// Mettre à jour le point focal\n\t\tthis.setFocusPoint(original.x, original.y);\n\t}\n\n\t/**\n\t * Gère le déplacement de l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleCropOverlayDrag(e) {\n\t\tconst deltaX = e.clientX - this.interaction.startMouseX;\n\t\tconst deltaY = e.clientY - this.interaction.startMouseY;\n\n\t\t// Calculer la nouvelle position en pixels d'affichage\n\t\tconst newX = this.interaction.startX + deltaX;\n\t\tconst newY = this.interaction.startY + deltaY;\n\n\t\t// Convertir en coordonnées originales\n\t\tconst original = this._toOriginalCoords(newX, newY);\n\n\t\t// Obtenir les dimensions actuelles en coordonnées originales\n\t\tconst { width, height } = this.state.cropZone;\n\n\t\t// Mettre à jour la zone de recadrage\n\t\tthis.setCropZone(original.x, original.y, width, height);\n\t}\n\n\t/**\n\t * Gère le redimensionnement de l'overlay de recadrage\n\t * @private\n\t * @param {MouseEvent} e - Événement mousemove\n\t */\n\t_handleCropOverlayResize(e) {\n\t\tif (!this.interaction.activeHandle) return;\n\n\t\tconst deltaX = e.clientX - this.interaction.startMouseX;\n\t\tconst deltaY = e.clientY - this.interaction.startMouseY;\n\n\t\tlet newX = this.interaction.startX;\n\t\tlet newY = this.interaction.startY;\n\t\tlet newWidth = this.interaction.startWidth;\n\t\tlet newHeight = this.interaction.startHeight;\n\n\t\t// Ajuster en fonction de la poignée active\n\t\tif (this.interaction.activeHandle.includes(\"t\")) {\n\t\t\t// Top\n\t\t\tnewY = this.interaction.startY + deltaY;\n\t\t\tnewHeight = this.interaction.startHeight - deltaY;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"b\")) {\n\t\t\t// Bottom\n\t\t\tnewHeight = this.interaction.startHeight + deltaY;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"l\")) {\n\t\t\t// Left\n\t\t\tnewX = this.interaction.startX + deltaX;\n\t\t\tnewWidth = this.interaction.startWidth - deltaX;\n\t\t}\n\t\tif (this.interaction.activeHandle.includes(\"r\")) {\n\t\t\t// Right\n\t\t\tnewWidth = this.interaction.startWidth + deltaX;\n\t\t}\n\n\t\t// Empêcher les dimensions négatives\n\t\tif (newWidth < 10) {\n\t\t\tif (this.interaction.activeHandle.includes(\"l\")) {\n\t\t\t\tnewX = this.interaction.startX + this.interaction.startWidth - 10;\n\t\t\t}\n\t\t\tnewWidth = 10;\n\t\t}\n\t\tif (newHeight < 10) {\n\t\t\tif (this.interaction.activeHandle.includes(\"t\")) {\n\t\t\t\tnewY = this.interaction.startY + this.interaction.startHeight - 10;\n\t\t\t}\n\t\t\tnewHeight = 10;\n\t\t}\n\n\t\t// Convertir les coordonnées d'affichage en coordonnées originales\n\t\tconst originalX = newX / this.state.scaleX;\n\t\tconst originalY = newY / this.state.scaleY;\n\t\tconst originalWidth = newWidth / this.state.scaleX;\n\t\tconst originalHeight = newHeight / this.state.scaleY;\n\n\t\t// Mettre à jour la zone de recadrage\n\t\tthis.setCropZone(originalX, originalY, originalWidth, originalHeight);\n\t}\n\n\t/**\n\t * Met à jour la position du marqueur de point focal\n\t * @private\n\t */\n\t_updateFocusMarkerPosition() {\n\t\tif (!this.state.focusMarker) return;\n\n\t\tconst { x, y } = this.state.focusPoint;\n\n\t\t// Limiter les coordonnées aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n\t\tconst clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n\n\t\t// Mettre à jour l'état si les coordonnées ont été limitées\n\t\tif (x !== clampedX || y !== clampedY) {\n\t\t\tthis.state.focusPoint = { x: clampedX, y: clampedY };\n\t\t}\n\n\t\tconst scaled = this._toScaledCoords(clampedX, clampedY);\n\n\t\t// LOGGING: Validate padding offset\n\t\tif (this.options.debug) {\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tconst paddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t\tconsole.log(\n\t\t\t\t\"[FocusMarker] scaled:\",\n\t\t\t\tscaled,\n\t\t\t\t\"paddingLeft:\",\n\t\t\t\tpaddingLeft,\n\t\t\t\t\"paddingTop:\",\n\t\t\t\tpaddingTop,\n\t\t\t\t\"containerRect:\",\n\t\t\t\tcontainer.getBoundingClientRect(),\n\t\t\t);\n\t\t}\n\n\t\t// Ajuster pour centrer le marqueur\n\t\t// Adjust for container padding (use unique variable names)\n\t\tlet focusPaddingLeft = 0;\n\t\tlet focusPaddingTop = 0;\n\t\t{\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tfocusPaddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tfocusPaddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t}\n\n\t\tthis.state.focusMarker.style.left = `${\n\t\t\tscaled.x + focusPaddingLeft - this.state.focusMarker.offsetWidth / 2\n\t\t}px`;\n\t\tthis.state.focusMarker.style.top = `${\n\t\t\tscaled.y + focusPaddingTop - this.state.focusMarker.offsetHeight / 2\n\t\t}px`;\n\t\tif (this.options.debug) {\n\t\t\tconsole.log(\n\t\t\t\t\"[FocusMarker] style.left:\",\n\t\t\t\tthis.state.focusMarker.style.left,\n\t\t\t\t\"style.top:\",\n\t\t\t\tthis.state.focusMarker.style.top,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Met à jour la position et les dimensions de l'overlay de recadrage\n\t * @private\n\t */\n\t_updateCropOverlayPosition() {\n\t\tif (!this.state.cropOverlay) return;\n\n\t\tconst { x, y, width, height } = this.state.cropZone;\n\n\t\t// Limiter aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n\t\tconst clampedY = Math.max(\n\t\t\t0,\n\t\t\tMath.min(y, this.state.originalHeight - height),\n\t\t);\n\t\tconst clampedWidth = Math.max(\n\t\t\t10,\n\t\t\tMath.min(width, this.state.originalWidth - clampedX),\n\t\t);\n\t\tconst clampedHeight = Math.max(\n\t\t\t10,\n\t\t\tMath.min(height, this.state.originalHeight - clampedY),\n\t\t);\n\n\t\t// Mettre à jour l'état si les valeurs ont été limitées\n\t\tif (\n\t\t\tx !== clampedX ||\n\t\t\ty !== clampedY ||\n\t\t\twidth !== clampedWidth ||\n\t\t\theight !== clampedHeight\n\t\t) {\n\t\t\tthis.state.cropZone = {\n\t\t\t\tx: clampedX,\n\t\t\t\ty: clampedY,\n\t\t\t\twidth: clampedWidth,\n\t\t\t\theight: clampedHeight,\n\t\t\t};\n\t\t}\n\n\t\t// Convertir en coordonnées d'affichage\n\t\tconst scaled = this._toScaledCoords(clampedX, clampedY);\n\t\tconst scaledWidth = clampedWidth * this.state.scaleX;\n\t\tconst scaledHeight = clampedHeight * this.state.scaleY;\n\n\t\t// LOGGING: Validate padding offset\n\t\tif (this.options.debug) {\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tconst paddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tconst paddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t\tconsole.log(\n\t\t\t\t\"[CropOverlay] scaled:\",\n\t\t\t\tscaled,\n\t\t\t\t\"paddingLeft:\",\n\t\t\t\tpaddingLeft,\n\t\t\t\t\"paddingTop:\",\n\t\t\t\tpaddingTop,\n\t\t\t\t\"containerRect:\",\n\t\t\t\tcontainer.getBoundingClientRect(),\n\t\t\t);\n\t\t}\n\n\t\t// Mettre à jour l'overlay\n\t\t// Adjust for container padding (use unique variable names)\n\t\tlet cropPaddingLeft = 0;\n\t\tlet cropPaddingTop = 0;\n\t\t{\n\t\t\tconst container = this.imageElement.parentNode;\n\t\t\tconst computedStyle = window.getComputedStyle(container);\n\t\t\tcropPaddingLeft = Number.parseFloat(computedStyle.paddingLeft);\n\t\t\tcropPaddingTop = Number.parseFloat(computedStyle.paddingTop);\n\t\t}\n\n\t\tthis.state.cropOverlay.style.left = `${scaled.x + cropPaddingLeft}px`;\n\t\tthis.state.cropOverlay.style.top = `${scaled.y + cropPaddingTop}px`;\n\t\tthis.state.cropOverlay.style.width = `${scaledWidth}px`;\n\t\tthis.state.cropOverlay.style.height = `${scaledHeight}px`;\n\t\tif (this.options.debug) {\n\t\t\tconsole.log(\n\t\t\t\t\"[CropOverlay] style.left:\",\n\t\t\t\tthis.state.cropOverlay.style.left,\n\t\t\t\t\"style.top:\",\n\t\t\t\tthis.state.cropOverlay.style.top,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Active ou désactive le point focal\n\t * @public\n\t * @param {boolean} active - État d'activation\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\ttoggleFocusPoint(active) {\n\t\tif (!this.options.focusPoint.enabled) return this;\n\n\t\tconst isActive = active === undefined ? !this.state.focusActive : active;\n\n\t\tif (active && !this.state.focusActive) {\n\t\t\t// Activer le point focal\n\t\t\tif (!this.state.focusMarker) {\n\t\t\t\tthis._createFocusMarker();\n\t\t\t}\n\n\t\t\t// Positionner au centre de l'image par défaut si pas déjà défini\n\t\t\tif (this.state.focusPoint.x === 0 && this.state.focusPoint.y === 0) {\n\t\t\t\tthis.state.focusPoint = {\n\t\t\t\t\tx: this.state.originalWidth / 2,\n\t\t\t\t\ty: this.state.originalHeight / 2,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t\tthis.state.focusMarker.style.display = \"block\";\n\t\t\tthis.state.focusActive = true;\n\t\t} else if (!active && this.state.focusActive) {\n\t\t\t// Désactiver le point focal\n\t\t\tif (this.state.focusMarker) {\n\t\t\t\tthis.state.focusMarker.style.display = \"none\";\n\t\t\t}\n\t\t\tthis.state.focusActive = false;\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Active ou désactive la zone de recadrage\n\t * @public\n\t * @param {boolean} active - État d'activation\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\ttoggleCropZone(active) {\n\t\tif (!this.options.cropZone.enabled) return this;\n\n\t\tconst isActive = active === undefined ? !this.state.cropActive : active;\n\n\t\tif (active && !this.state.cropActive) {\n\t\t\t// Activer la zone de recadrage\n\t\t\tif (!this.state.cropOverlay) {\n\t\t\t\tthis._createCropOverlay();\n\t\t\t}\n\n\t\t\t// Définir une zone par défaut si pas déjà définie\n\t\t\tif (this.state.cropZone.width === 0 || this.state.cropZone.height === 0) {\n\t\t\t\tconst defaultWidth = this.state.originalWidth / 2;\n\t\t\t\tconst defaultHeight = this.state.originalHeight / 2;\n\t\t\t\tconst defaultX = (this.state.originalWidth - defaultWidth) / 2;\n\t\t\t\tconst defaultY = (this.state.originalHeight - defaultHeight) / 2;\n\n\t\t\t\tthis.state.cropZone = {\n\t\t\t\t\tx: defaultX,\n\t\t\t\t\ty: defaultY,\n\t\t\t\t\twidth: defaultWidth,\n\t\t\t\t\theight: defaultHeight,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis._updateCropOverlayPosition();\n\t\t\tthis.state.cropOverlay.style.display = \"block\";\n\t\t\tthis.state.cropActive = true;\n\t\t} else if (!active && this.state.cropActive) {\n\t\t\t// Désactiver la zone de recadrage\n\t\t\tif (this.state.cropOverlay) {\n\t\t\t\tthis.state.cropOverlay.style.display = \"none\";\n\t\t\t}\n\t\t\tthis.state.cropActive = false;\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Définit la position du point focal\n\t * @public\n\t * @param {number} x - Coordonnée X en pixels originaux\n\t * @param {number} y - Coordonnée Y en pixels originaux\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\tsetFocusPoint(x, y) {\n\t\t// Limiter les coordonnées aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth));\n\t\tconst clampedY = Math.max(0, Math.min(y, this.state.originalHeight));\n\n\t\tthis.state.focusPoint = { x: clampedX, y: clampedY };\n\n\t\tif (this.state.focusActive && this.state.focusMarker) {\n\t\t\tthis._updateFocusMarkerPosition();\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Définit la position et les dimensions de la zone de recadrage\n\t * @public\n\t * @param {number} x - Coordonnée X en pixels originaux\n\t * @param {number} y - Coordonnée Y en pixels originaux\n\t * @param {number} width - Largeur en pixels originaux\n\t * @param {number} height - Hauteur en pixels originaux\n\t * @returns {ImageTool} Instance pour chaînage\n\t */\n\tsetCropZone(x, y, width, height) {\n\t\t// Limiter aux dimensions de l'image\n\t\tconst clampedX = Math.max(0, Math.min(x, this.state.originalWidth - width));\n\t\tconst clampedY = Math.max(\n\t\t\t0,\n\t\t\tMath.min(y, this.state.originalHeight - height),\n\t\t);\n\t\tconst clampedWidth = Math.max(\n\t\t\t10,\n\t\t\tMath.min(width, this.state.originalWidth - clampedX),\n\t\t);\n\t\tconst clampedHeight = Math.max(\n\t\t\t10,\n\t\t\tMath.min(height, this.state.originalHeight - clampedY),\n\t\t);\n\n\t\tthis.state.cropZone = {\n\t\t\tx: clampedX,\n\t\t\ty: clampedY,\n\t\t\twidth: clampedWidth,\n\t\t\theight: clampedHeight,\n\t\t};\n\n\t\tif (this.state.cropActive && this.state.cropOverlay) {\n\t\t\tthis._updateCropOverlayPosition();\n\t\t}\n\n\t\t// Notifier le changement\n\t\tthis._notifyChange();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Obtient la position actuelle du point focal\n\t * @public\n\t * @returns {Object} Coordonnées du point focal {x, y}\n\t */\n\tgetFocusPoint() {\n\t\treturn { ...this.state.focusPoint };\n\t}\n\n\t/**\n\t * Obtient la position et les dimensions actuelles de la zone de recadrage\n\t * @public\n\t * @returns {Object} Zone de recadrage {x, y, width, height}\n\t */\n\tgetCropZone() {\n\t\treturn { ...this.state.cropZone };\n\t}\n\n\t/**\n\t * Obtient les dimensions originales de l'image\n\t * @public\n\t * @returns {Object} Dimensions {width, height}\n\t */\n\tgetImageDimensions() {\n\t\treturn {\n\t\t\twidth: this.state.originalWidth,\n\t\t\theight: this.state.originalHeight,\n\t\t};\n\t}\n\n\t/**\n\t * Notifie les changements via le callback\n\t * @private\n\t */\n\t_notifyChange() {\n\t\tif (typeof this.options.onChange === \"function\") {\n\t\t\tthis.options.onChange({\n\t\t\t\tfocusPoint: this.getFocusPoint(),\n\t\t\t\tcropZone: this.getCropZone(),\n\t\t\t\tfocusActive: this.state.focusActive,\n\t\t\t\tcropActive: this.state.cropActive,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Détruit l'instance et nettoie les ressources\n\t * @public\n\t */\n\tdestroy() {\n\t\t// Supprimer les éléments DOM\n\t\tif (this.state.focusMarker?.parentNode) {\n\t\t\tthis.state.focusMarker.parentNode.removeChild(this.state.focusMarker);\n\t\t}\n\n\t\tif (this.state.cropOverlay?.parentNode) {\n\t\t\tthis.state.cropOverlay.parentNode.removeChild(this.state.cropOverlay);\n\t\t}\n\n\t\t// Supprimer les écouteurs d'événements\n\t\twindow.removeEventListener(\"resize\", this._updateScaling.bind(this));\n\t\tdocument.removeEventListener(\"mouseup\", this._handleMouseUp.bind(this));\n\t\tdocument.removeEventListener(\"mousemove\", this._handleMouseMove.bind(this));\n\n\t\t// Réinitialiser l'état\n\t\tthis.state = null;\n\t\tthis.interaction = null;\n\t\tthis.options = null;\n\t\tthis.imageElement = null;\n\t}\n}\n\n// Exporter la classe\nexport default VisualImageTool;\n"],"names":["VisualImageTool","constructor","options","imageElement","Error","this","document","querySelector","tagName","focusPoint","enabled","style","width","height","border","boxShadow","backgroundColor","cropZone","handleStyle","onChange","debug","state","focusMarker","cropOverlay","focusActive","cropActive","x","y","originalWidth","originalHeight","displayWidth","displayHeight","scaleX","scaleY","interaction","focusDragging","focusDragOffsetX","focusDragOffsetY","cropDragging","cropResizing","activeHandle","startX","startY","startWidth","startHeight","startMouseX","startMouseY","_init","_prepareContainer","_updateScaling","_createFocusMarker","_createCropOverlay","_setupEventListeners","parentNode","position","naturalWidth","naturalHeight","offsetWidth","offsetHeight","_updateFocusMarkerPosition","_updateCropOverlayPosition","_toOriginalCoords","scaledX","scaledY","_toScaledCoords","originalX","originalY","marker","createElement","cursor","display","zIndex","clipPath","appendChild","addEventListener","_handleFocusMarkerMouseDown","bind","e","rect","getBoundingClientRect","clientX","left","clientY","top","preventDefault","overlay","boxSizing","handles","handleType","handle","dataset","marginLeft","right","marginTop","bottom","_handleCropHandleMouseDown","_handleCropOverlayMouseDown","Number","parseInt","stopPropagation","target","window","complete","_handleMouseUp","_handleMouseMove","body","_handleFocusMarkerDrag","_handleCropOverlayDrag","_handleCropOverlayResize","imageRect","targetScaledX","targetScaledY","original","setFocusPoint","deltaX","deltaY","newX","newY","setCropZone","newWidth","newHeight","includes","clampedX","Math","max","min","clampedY","scaled","container","computedStyle","getComputedStyle","paddingLeft","parseFloat","paddingTop","console","log","focusPaddingLeft","focusPaddingTop","clampedWidth","clampedHeight","scaledWidth","scaledHeight","cropPaddingLeft","cropPaddingTop","toggleFocusPoint","active","undefined","_notifyChange","toggleCropZone","defaultWidth","defaultHeight","defaultX","defaultY","getFocusPoint","getCropZone","getImageDimensions","destroy","removeChild","removeEventListener"],"mappings":"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"}
|