Click and drag images to lock in a specified area

I apologize for not posting this sooner - current situation has really thrown a wrench in things. Here is code that was done by David. It works beautifully on line. It doesn’t lock pieces in place, but it does do a very nice drag and drop. I’ll do the python first then JS.

Note: This is David Bridge’s Code, so I have cited him as the author of the code on my experiment.

In Begin Experiment Tab:

def createPiece(piece, pos, name):
    return visual.ImageStim(win, image=piece.image, name=name, size=piece.size, pos=pos)

def drawPicked(picked):
    for each in picked:
        each.draw()

def movePicked(picked, mouse, grabbed):
    if grabbed is not None and mouse.isPressedIn(grabbed):
        grabbed.pos = mouse.getPos()
        return grabbed
    else:
        for piece in picked:
            if mouse.isPressedIn(piece) and grabbed is None:
                return piece



def createGrid(rows, size, pos, names):
    inc = (size/rows)
    rowStart = pos[0] - size/2
    colStart = pos[1] + size/2
    row, col = rowStart  + inc/2, colStart - inc/2
    counter = 0
    
    grid = []
    for i in range(rows):
        for j in range(rows):
            grid.append(visual.Rect(win, name=names[counter], units='height', size = [size/rows, size/rows], pos= [row,col], lineColor= [-1.000,0.184,0.184]))
            row += inc
            counter += 1
        col -= inc
        row = rowStart + inc/2
    return grid

def drawGrid(grid):
    for i in grid:
        i.draw()

def checkAnswer(grid, pieces):
    # Get names of pieces that were picked
    picNames = [pic.image for pic in pieces]
    correctPieces = []
    for cell in grid:
        # Check if piece has been picked
        if cell.name in picNames:
            for name in range(0, len(picNames)):
                if cell.name == picNames[name]:
                    if cell.contains(pieces[name].pos):
                        correctPieces.append(True)
                        break # Piece found, go to next cell
        else:
            return False  # Correct piece not picked
    return len(correctPieces) == len(grid)
    

In Begin Routine Tab:

continueRoutine = True
pieces = [p1a, p2a, p3a, p4a, p5a, p6a]
answers = [a1,a2,a3,a4,a5,a6,a7,a8,a9]
picked = []
newPiece = None
movingPiece = None
grid = createGrid(nRows1, size, polygon.pos, answers)
polygon.setFillColor(None)

In Each Frame Tab:

for piece in pieces:
    if mouse.isPressedIn(piece) and newPiece == None:
        newPiece = createPiece(piece, mouse.getPos(), piece.image)
        picked.append(newPiece)
        
    
if newPiece is not None and mouse.getPressed()[0] == 0:
    newPiece = None

movingPiece = movePicked(picked, mouse, movingPiece)
drawGrid(grid)
drawPicked(picked)

JS in Begin Experiment Tab:

createPiece = function(piece, pos, name){
  return new visual.ImageStim({win : psychoJS.window,
                                image: piece.image, 
                                name: name,
                                size: piece.size, 
                                pos: pos})
}

drawPicked = function(picked, draw) {
  if (picked.length > 0) {
    for(let each of picked) {
      each.autoDraw = draw;
    }
  }
}

movePicked = function(picked, mouse, grabbed) {
  if (grabbed != 'undefined' &&  mouse.getPressed()[0] === 1) {
    grabbed.pos = mouse.getPos();
    return grabbed
  } else {
      for (let piece of picked) {
        if (piece.contains(mouse) &&  mouse.getPressed()[0] === 1 && grabbed === 'undefined'){
          piece.pos = mouse.getPos();
          return piece;
        }
      }
   return 'undefined'
  }
}

createGrid = function(rows, size, pos, names) {
    var inc = (size/rows);
    var rowStart = pos[0] - size/2;
    var colStart = pos[1] + size/2;
    var row = rowStart  + inc/2;
    var col = colStart - inc/2;
    var counter = 0;
    var grid = [];
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < rows; j++) {
            grid.push(new visual.Rect({win : psychoJS.window,
                                        name: names[counter], 
                                        units: 'height',
                                        lineColor: new util.Color([0,0,0]),
                                        size: [size/rows, size/rows], 
                                        pos: [row,col]}))
            row += inc
            counter += 1
        }
        col -= inc
        row = rowStart + inc/2
    }
    return grid
}


drawGrid = function(grid, draw) {
    for (let i of grid) {
        i.autoDraw = draw;
    }
}

checkAnswer = function(grid, pieces) {
    var picNames = pieces.map((pic) => pic.name)
    var correctPieces = []
    for (let cell of grid) {
        if (picNames.includes(cell.name)) {
            for (let name = 0; name < picNames.length; name++) {
                if (cell.name === picNames[name]) {
                    if (cell.contains(pieces[name])) {
                        correctPieces.push(true)
                        break
                    }
                }
            }
        } else {
            return false
        }
    }
    return correctPieces.length === grid.length
} 

picNameDict = {p1a: "pcetl.png",
               p2a: "pcetr.png", 
               p3a: "pcered.png",
               p4a: "pcebl.png",
               p5a: "pcebr.png",
               p6a: "pcewte.png",
               p1b: "pcetl.png",
               p2b: "pcetr.png", 
               p3b: "pcered.png",
               p4b: "pcebl.png",
               p5b: "pcebr.png",
               p6b: "pcewte.png",
               }

In Begin Routine Tab:

pieces = [p1a, p2a, p3a, p4a, p5a, p6a]
answers = [a1,a2,a3,a4,a5,a6,a7,a8,a9]
picked = []
newPiece = 'undefined'
movingPiece = 'undefined'
grid = createGrid(nRows1, size, polygon.pos, answers)

In Each Frame Tab:

for (let piece of pieces) {
    if (piece.contains(mouse) && mouse.getPressed()[0] === 1 && newPiece === 'undefined') {
        newPiece = createPiece(piece, mouse.getPos(), picNameDict[piece.name])
        picked.push(newPiece)
    }
}
        
    
if (newPiece !== 'undefined' && mouse.getPressed()[0] === 0) {
    newPiece = 'undefined'
}

movingPiece = movePicked(picked, mouse, movingPiece)
drawGrid(grid, true)
drawPicked(picked, true)

if (t > .5 && nextButton.contains(mouse) && mouse.getPressed()[0] === 1) {
  continueRoutine = false
}

In End Routine Tab:

piece = drawPicked(picked, false, piece)
drawGrid(grid, false)
nextButton.setAutoDraw(false)

Good Luck!