Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New center and zoom options #89

Open
gniuslab opened this issue Jan 5, 2023 · 11 comments
Open

New center and zoom options #89

gniuslab opened this issue Jan 5, 2023 · 11 comments
Assignees

Comments

@gniuslab
Copy link

gniuslab commented Jan 5, 2023

Resume

I plan to change the way in which Pikaso creates the container, to give the possibility to center the image anything natively with an algorithm instead of using a css trick to center the background image to the stage, and additionally the function of zoomIn and zoomOut

Example of implementation to center any shape in stage for example in file Background.ts:125

if (options.size === 'resize') {
  this.board.centerAndFitShape(this.image.node)
}
/**
 * Centers the stage and fit especific shape
 * @param {Konva.Shape} shape
 * @param {number} padding = 2
 * @example
 * ```ts
 * editor.board.centerAndFitShape(Konva.Shape)
 * ```
 */
centerAndFitShape(shape, padding = 2) {
  padding = padding || 0

  const rawShapeRect = shape.getClientRect({ relativeTo: this.stage }), // Note: getClientRect gives size based on scaling - we want unscaled size so use 'relativeTo: stage' param to ensure consistent measurements.

    paddedShapeRect = {
      x: rawShapeRect.x - padding,
      y: rawShapeRect.y - padding,
      width: rawShapeRect.width + (2 * padding),
      height: rawShapeRect.height + (2 * padding)
    },

    viewRect = {
      width: Math.min(this.stage.width(), this.container.offsetWidth),
      height: Math.min(this.stage.height(), this.container.offsetHeight)
    },

    widthRatio = viewRect.width / paddedShapeRect.width, heightRatio = viewRect.height / paddedShapeRect.height,

    scale = widthRatio > heightRatio ? heightRatio : widthRatio,

    centeringAjustment = {
      x: (viewRect.width - paddedShapeRect.width * scale) / 2,
      y: (viewRect.height - paddedShapeRect.height * scale) / 2
    },

    finalPosition = {
      x: centeringAjustment.x + (-paddedShapeRect.x * scale),
      y: centeringAjustment.y + (-paddedShapeRect.y * scale)
    }

  this.stage.to({
    x: finalPosition.x,
    y: finalPosition.y,
    scaleX: scale,
    scaleY: scale,
    duration: 0.1
  })
}
/**
 * Zoom the stage
 * @param {number} scaleBy
 * @see zoomIn = 1.2, zoomOut = 0.8
 */
zoom (scaleBy) {
  const oldScale = this.stage.scaleX()

  // Calculate the center of the stage
  const pos = {
    x: this.stage.width() / 2,
    y: this.stage.height() / 2
  }

  // Calculate the position of the mouse relative to the stage
  const mousePointTo = {
    x: pos.x / oldScale - this.stage.x() / oldScale,
    y: pos.y / oldScale - this.stage.y() / oldScale
  }

  // Calculate the new scale of the stage
  const newScale = Math.max(0.05, oldScale * scaleBy)

  // Calculate the new position of the stage to keep it centered
  const newPos = {
    x: -(mousePointTo.x - pos.x / newScale) * newScale,
    y: -(mousePointTo.y - pos.y / newScale) * newScale
  }

  // Update the stage with the new position and scale
  this.stage.to({
    x: newPos.x,
    y: newPos.y,
    scaleX: newScale,
    scaleY: newScale,
    duration: 0.1
  })
}
@gniuslab
Copy link
Author

gniuslab commented Jan 6, 2023

I am going to work on an algorithm that serves to pan and zoom with the mouse to integrate it if these recommendations are approved

@raminious
Copy link
Contributor

Hey @gniuslab
It is fantastic that you are proposing adding Zooming to the core project, which is also being requested here: #28

However, I am having difficulty understanding what the real use case is for centerAndFitShape.
Let's talk about that in more detail.

@gniuslab
Copy link
Author

gniuslab commented Jan 7, 2023

Hi @raminious , the use case of the centerAndFitShape function is quite trivial to make things uncenterable if they go off-canvas, you can see how it works in detail here...

https://codepen.io/JEE42/pen/ExEgeMX

Do this exercise, move one of the red squares out of your vision and click on Fit rect group to stage

@raminious
Copy link
Contributor

@gniuslab Is there any progress on the zooming feature?

@gniuslab
Copy link
Author

gniuslab commented Feb 4, 2023

@raminious Yes, I can implement it, but I don't know the process of how to do it, in your main branch...

@ProjetNice
Copy link

think you ,You guys are the best.

@ProjetNice
Copy link

@raminious This only solves the scaling problem, but does not solve the box selection x y offset problem.Sorry, my English is not good
IMG_2314

@ProjetNice
Copy link

This is my code

`stage.on('wheel', (e) => {
e.evt.preventDefault();
let oldScale = stage.scaleX();
let scaleBy=1.1
let mousePointTo = {
x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale,
};

let newScale = e.evt.deltaY > 0 ? oldScale / scaleBy : oldScale * scaleBy ;
stage.scale({ x: newScale, y: newScale });


let newPos = {
  x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
  y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale,
};

stage.position(newPos);
stage.batchDraw();

});`

@gniuslab
Copy link
Author

@ProjetNice Use getRelativePointerPosition

@ProjetNice
Copy link

I still can't do this effect, I would like to add this feature and add it in the documentation, which is very helpful for beginners
1689832586468 -original-original

@ProjetNice
Copy link

I solved that problem, and this is my demo, using the vue framework

<template>
  <button @click="addPolygon">addPolygon</button>
  <button @click="changeDrag">changeDrag</button>

  <div id="editor" ref="root"></div>

</template>

<script setup>
import {ref, onMounted} from "vue";
import {Pikaso} from "pikaso";

let editor;
let stage;
let layer
let board
let selection

const root = ref(null);
let dragFlag=false

onMounted(() => {
  editor = new Pikaso({
    container: root.value,
    selection: {
      transformer: {
        borderStroke: "#1890ff",
        borderStrokeWidth: 0.5,
        anchorFill: "#1890ff",
        anchorSize: 10,
      },
      zone:{
        fill:"#1890ff50",
        stroke:'#1890ff',
      }
    },
  });
  editor.board.background.fill('rgba(0,0,0,0.5)')
  stage=editor.board.stage
  layer=editor.board.layer
  board=editor.board
  selection=board.selection
  
  /**
   * Used to calibrate mouse position
   */
  stage.on("mousemove touchmove",(e)=>{
    let zoom=selection.zone
    let x=zoom.attrs.x
    let y=zoom.attrs.y
    let width=zoom.attrs.width
    let height=zoom.attrs.height
    let sx=stage.x()
    let sy=stage.y()
    let scx=stage.scaleX()
    let scy=stage.scaleY()
    zoom.attrs.x = (x - sx) / scx;
    zoom.attrs.y = (y - sy) / scy;
    zoom.attrs.width=width/scx
    zoom.attrs.height=height/scy
  })
  /**
   * Resize the canvas
   */
  stage.on('wheel', (e) => {
    e.evt.preventDefault();
    let oldScale = stage.scaleX();
    let scaleBy=1.1
    let mousePointTo = {
      x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
      y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale,
    };

    let newScale = e.evt.deltaY > 0 ? oldScale / scaleBy : oldScale * scaleBy ;
    stage.scale({ x: newScale, y: newScale });


    let newPos = {
      x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
      y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale,
    };

    stage.position(newPos);
    stage.batchDraw();
  });

})
function addPolygon() {
  editor.shapes.polygon.insert({
    x: 250,
    y: 250,
    radius: 90,
    sides: 6,
    fill: "#fafafa",
  });
}
function changeDrag(){
  stage.draggable(!dragFlag)
  dragFlag=!dragFlag
}
</script>
<style>
#editor {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
</style>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants