Depuis longtemps, je galère pour zoomer mes graph sous excel alors que certain logiciels font
çà de manière ultra simple (à la souris)
Après de nombreuse recherches sur internet, pour trouver un gentil programmeur qui aurais fais
une macro qui va bien,je n'ai rien trouvé de concluant.
Je me suis donc décidé à me mettre au VBA pour implémenter ce zoom.
Après de long mois de travail (je débutais!!) et de nombreuse approches
et problématiques(dont je vous passerais les détail),
j'ai le plaisir de vous faire partager mon code:
Cet outil de Zoom pour Excel permet:
- de faire un zoom à la souris en traçant un rectangle en cliquant sur "F2"
- de déplacer la courbe en bougeant la souris avec Ctrl appuyé
- faire un retour aux échelles auto en faisant "Ctrl a"
- faire un retour aux échelles auto par clic droit (seulement sur XL2000)
J'utilise les événement graphiques dans un module de classe
pour l'utiliser, copiez la première partie du code dans Thisworkbook
et la seconde dans un module de classe appelé classe_zoom
Source / Exemple :
'Dans Thisworkbook:
Dim myclassmodule As New classe_zoom
Private Sub Workbook_Open()
Call charge_class
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Call charge_class
End Sub
Private Sub charge_class()
Dim graph As String
'on cherche si il y a un graph , on passe à l'instruction suivante si il n'y en a pas
On Error Resume Next
graph = ActiveChart.Name
' on attribut le lancement du zoom à F2 si il y a un graph sur la feuille
If graph <> Empty Then
'on déclare le module de classe pour la feuille active
Set myclassmodule.mychartclass = ActiveChart
Application.OnKey "{F2}", "ThisWorkbook.zoom"
Application.OnKey "^a", "thisworkbook.echelle_auto"
ActiveSheet.Unprotect
Else
Application.OnKey "{F2}"
Application.OnKey "^a"
End If
'ajout du menu retour echelle auto
Application.CommandBars("plot area").Reset
With Application.CommandBars("plot area").Controls.Add(msoControlButton, Before:=1, temporary:=True)
.Caption = "Retour echelle auto" 'le nom de la commande
.BeginGroup = True 'ligne facultative si elle est précisée alors
.OnAction = "thisworkbook.echelle_auto" ' la macro 1 est lancé
End With
End Sub
'on met cette macro dans le thisworkbook afin d'avoir tous nos outils de zoom
'dans un seul module de classe classe_zoom (pas d'ajour d'autre module)
Private Sub zoom()
Call myclassmodule.zoom_souris
End Sub
Public Sub echelle_auto()
Call myclassmodule.retour_echelle_auto
End Sub
'Dans un module de classe nommé classe_zoom
Option Explicit
Public WithEvents mychartclass As Chart
Dim X0 As Long, Y0 As Long
Dim top_rect As Long, left_rect As Long
Dim top_graph As Single, left_graph As Single
Dim timer As Long, nb_shape As Integer
Dim ax As Axis
'déclaration des tableaux pour les collections
Dim dimension_graph(2) As Long, dimension_rect(2) As Long
Dim axe_min(2, 2) As Single, axe_max(2, 2) As Single
Dim axe_new_echelle(2, 2) As Single, axe_echelle(2, 2) As Single, ratio_echelle(2, 2) As Single
Dim unite_princ As Variant
Dim axe_max_new(2, 2) As Single, axe_min_new(2, 2) As Single
Dim delta_souris(2) As Long
Dim i As Long, j As Long
Const sensibilite = 5
Private Sub mychartclass_MouseMove(ByVal Button As Long, ByVal Shift As Long, ByVal x As Long, ByVal y As Long)
Application.StatusBar = "x=" & x & " " & "y=" & y
If Shift = 0 Then
'Quand Ctrl n'est pas enfoncé, on récupére les coordonnées origine et les axes
X0 = x
Y0 = y
For Each ax In ActiveChart.Axes
With ax
i = .Type 'type d'axe x ou y
j = .AxisGroup 'groupe d'axe principal ou secondaire
axe_min(i, j) = .MinimumScale
axe_max(i, j) = .MaximumScale
End With
Next
Application.Cursor = xlNormal
End If
If Shift = 2 Then 'si Ctrl est appuyé
If Button = 0 Then 'pour ne pas activer la fonction si on clique le bouton de la souris
ActiveChart.Deselect 'On enleve toute selection pour faire plus propre
Application.Cursor = 1
Application.ScreenUpdating = False
'on calcule le mouvement de la souris en X et en Y
delta_souris(1) = X0 - x
delta_souris(2) = y - Y0 'sur Y on inverse car le zéro de la souris est en haut du graph
Application.StatusBar = "Dx=" & delta_souris(1) & " " & "Dy=" & delta_souris(2)
For Each ax In ActiveChart.Axes
With ax
i = .Type 'type d'axe x ou y
j = .AxisGroup 'groupe d'axe principal ou secondaire
unite_princ = .MajorUnit
'on ajoute aux valeur origine des axes, la variation de la souris divisé
'par la a sensibilité et pondérée de l'unité principale de l'axe
axe_min_new(i, j) = axe_min(i, j) + (unite_princ * delta_souris(i) / sensibilite)
axe_max_new(i, j) = axe_max(i, j) + (unite_princ * delta_souris(i) / sensibilite)
'on entre les nouvelles echelles arrondi sur la base de l'unité principale
.MaximumScale = Round((axe_max_new(i, j) / unite_princ), 0) * unite_princ
.MinimumScale = Round((axe_min_new(i, j) / unite_princ), 0) * unite_princ
.CrossesAt = .MinimumScale
End With
Next
End If 'if button
End If ' if shift=2
End Sub
Function zoom_souris()
'on trace le rectangle
ActiveChart.Select 'on selectionne la graph pour ne pas planter sous XL2007
Application.CommandBars("Drawing").Controls("Rectangle").Execute
modif_echelle
End Function
Function modif_echelle()
'on attend que le rectangle soit tracé en comptant les shapes sur la feuille
'peut être amélioré si on arrive a créer directement le rectangle nommé fenetre_zoom,
'on testerait alors sur l'existence de celui-ci
nb_shape = ActiveChart.Shapes.Count
timer = 0
Do While ActiveChart.Shapes.Count <= nb_shape
DoEvents 'Pour ne pas bloquer les actions sur l'userform pendant le tracé du graphe on utilise fonction DoEvents
'on fait une petite tempo afin de ne pas être bloqué dans la boucle
If timer = 100000 Then
MsgBox "zoom annulé"
Exit Function
End If
timer = timer + 1
Loop
Application.ScreenUpdating = False
'Selection.ShapeRange.Fill.Visible = msoFalse
Selection.Name = "fenetre_zoom"
'mesure du rectangle
With ActiveChart.Shapes("fenetre_zoom")
top_rect = .Top
left_rect = .Left
dimension_rect(1) = .Width 'Largeur
dimension_rect(2) = .Height 'hauteur
.Delete 'on efface le rectangle
End With
'mesure du cadre graphique
With ActiveChart.PlotArea
top_graph = .InsideTop
left_graph = .InsideLeft
dimension_graph(1) = .InsideWidth 'Largeur
dimension_graph(2) = .InsideHeight 'hauteur
End With
For Each ax In ActiveChart.Axes
With ax
i = .Type 'type d'axe x ou y
j = .AxisGroup 'groupe d'axe principal ou secondaire
axe_min(i, j) = .MinimumScale
axe_max(i, j) = .MaximumScale
axe_echelle(i, j) = axe_max(i, j) - axe_min(i, j)
'On calcule le ratio entre les échelle actuelle et les dimensions du graph
ratio_echelle(i, j) = (axe_echelle(i, j) / dimension_graph(i))
'On calcule donc la nouvelle échelle a partir du rectangle dessiné (Largeur en X et hauteur en Y)
axe_new_echelle(i, j) = dimension_rect(i) * ratio_echelle(i, j)
'On calcule l'échelle des X
'ici on part de la gauche on commence donc par Xmin
axe_min_new(1, 1) = axe_min(1, 1) + ((left_rect - left_graph) * ratio_echelle(1, 1))
axe_max_new(1, 1) = axe_min_new(1, 1) + axe_new_echelle(1, 1)
'on modifie les echelles Y principale et secondaire
'On soustrait la position du rectangle(rationnée et recalé) a l'echelle max
axe_max_new(2, j) = axe_max(2, j) - ((top_rect - top_graph) * ratio_echelle(2, j))
axe_min_new(2, j) = axe_max_new(2, j) - axe_new_echelle(2, j)
'On détermine le format de l'axe pour arrondir au nombre de chiffres
'de l'unité principale (cela évite d'avoir 12 chiffres après la virgule)
unite_princ = .MajorUnit
'on entre les nouvelles echelles arrondi sur la base de l'unité principale
.MinimumScale = Round((axe_min_new(i, j) / unite_princ), 0) * unite_princ
.MaximumScale = Round((axe_max_new(i, j) / unite_princ), 0) * unite_princ
.MajorUnitIsAuto = True 'on active l'unité principale pour avoir un recalcul
.MajorUnitIsAuto = False 'on la désactive pour ne pas avoir de recalcul quand on glisse la courbe
End With
Next
Application.ScreenUpdating = True
End Function
Function retour_echelle_auto()
Application.ScreenUpdating = False
For Each ax In ActiveChart.Axes
With ax
.MinimumScaleIsAuto = True
.MaximumScaleIsAuto = True
.MinorUnitIsAuto = True
.MajorUnitIsAuto = True
.MinorUnitIsAuto = False
.MajorUnitIsAuto = False
.CrossesAt = 0
End With
Next
Application.ScreenUpdating = True
End Function
Conclusion :
Je l'ai pas mal testé sur XL2000 mais quasiment pas sur 2007 et pas du tout sur 2010
Je n'arrive pas à faire fonctionner le menu contextuel sur 2007, j'ai l'impression que ce n'est pas
possible, mais si quelqu'un à la réponse, je suis preneur.
De même j'ai un léger effet sapin de noël sur le déplacement de courbe sous XL2000.
J'avais aussi pensé à en faire une macro complémentaire afin de pouvoir l'utiliser sur n'importe
quel fichier. Mais je ne sais pas encore comment faire et je ne me suis pas encore penché sur la
question.
Je pense que ce seras pour un prochaine évolution.
Je suis à votre écoute pour toutes correction de bug éventuel ou pour des amélioration
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.