5

Background: Suppose I have something like this:

 DynamicModule[{pt1 = {0, 0}, pt2 = {0, 1}, pt3 = {1, 0}},
  Graphics[Polygon[{pt1, pt2, pt3}], PlotRange -> 1]]

which I would like to change into this via a mouse click on the Polygon into this:

 DynamicModule[
  {pt1 = {0, 0}, pt2 = {0, 1}, pt3 = {1, 0}},
  Manipulate[
   Graphics[Polygon[{pt1, pt2, pt3}], PlotRange -> 1],
   {{pt1, {0, 0}}, Locator}, {{pt2, {0, 1}}, Locator}, {{pt3, {1, 0}}, 
    Locator}]]

Question: What code should I add to one of the snippets above to achieve this?

rm -rf
  • 88,781
  • 21
  • 293
  • 472
nilo de roock
  • 9,657
  • 3
  • 35
  • 77
  • You could see this question and its answers: http://mathematica.stackexchange.com/questions/4179/how-to-interactively-create-a-polygon-in-a-graphic – FJRA Apr 13 '12 at 13:25
  • FJRA, I know, I asked the question myself. I am still learning Dynamic, it is hard but I am getting there with your help. :-) – nilo de roock Apr 13 '12 at 13:34
  • Sorry, I didn't noticed it's you :P. Anyway it's good to have the link as reference for anyone who lands in this related question. – FJRA Apr 13 '12 at 13:36

1 Answers1

9

Here are two possible solutions. In both cases, one click brings locators up, another click will make them disappear.

Solution 1

Using multiple dynamic locators. The Map (or /@) is needed, since Dynamic inside Locator should have evaluated part number for pts.

DynamicModule[{pts = {{0, 0}, {0, 1}, {1, 0}}, locs = {}}, 
 Graphics[{EventHandler[
    Polygon[Dynamic[
      pts]], {"MouseClicked" :> (locs = 
        If[locs === {}, 
         Locator[Dynamic[pts[[#]]]] & /@ Range[Length[pts]], {}])}], 
   Dynamic[locs]}, PlotRange -> 1, PlotRangePadding -> Scaled[.05]]]

A slightly weird behavior of locators (washed out color when it appears first)... which I don't know why.

Solution 2

Using LocatorPane. Simpler, but Dynamic needs to refresh both locPts and pts when locs is assigned (Dynamic[expr, f] syntax).

DynamicModule[{pts = {{0, 0}, {0, 1}, {1, 0}}, locPts = {}},
 LocatorPane[Dynamic[locPts, (If[locPts =!= {}, pts = locPts = #]) &], 
  Graphics[{EventHandler[
     Polygon[Dynamic[
       pts]], {"MouseClicked" :> (locPts = If[locPts === {}, pts, {}])}]},
    PlotRange -> 1, PlotRangePadding -> Scaled[.05]]]]
Yu-Sung Chang
  • 7,061
  • 1
  • 39
  • 31
  • Sorry, I upped your answer, but I forgot to accept. Thanks again for your excellent answer. ( The fog that hang over DynamicModule is -finally- beginning to fade! ) – nilo de roock Apr 13 '12 at 20:24