Code Monkey home page Code Monkey logo

pikaso's People

Contributors

dependabot[bot] avatar raminious avatar snyk-bot avatar zthomas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pikaso's Issues

[ Feature ] Support Import/Export JSON

I think this is important to be able save the current state to json to be able save that and restore that later by importing the exported json

  • Export to json
  • Import from json

Help getting started with svelte

Hello

I'm trying to get started using Pikaso with Svelte.

This is what I'm trying:

<script lang="ts">
    import Pikaso from 'pikaso'
    import { onMount } from 'svelte';
    let editor;

    onMount(async () => {

        editor = new Pikaso({
        container: editor,
      });

      editor.shapes.polygon.insert({
        x: 250,
        y: 250,
        radius: 90,
        sides: 6,
        fill: "tomato",
      });
    });


    
</script>

<div bind:this={editor}>
   
</div>

However, I'm getting this error:

global is not defined

@http://localhost:3000/node_modules/.vite/pikaso.js?v=3f3cda72:9974:1

Any help is appreciated.

Shapes: Snap shape to other shapes/guidelines

I know this is a must need for designers. But just a nice to have, so, low priority.

As seen in this Konva.js demo, the ability to precisely snap to other shapes, helps designers create pixel perfect designs in a shorter cycles.

We can add following functionalities as part of this:

  • Align to horizontal centre
  • Align to vertical centre

I am not sure where the code goes, will leave that to your judgement.

Layers: Layers are currently anonymous and cannot be identified by name/slug/id

It would be lovely if Layers had a name or id to uniquely identify it. This would be handy when naming the layer inside the Canvas Editor.

Maybe create a LayerModel or something...

pikaso/src/Board/index.ts

Lines 28 to 297 in 48d0abd

public readonly layer: Konva.Layer
/**
* The html container element which the editor renders into that
*/
public readonly container: HTMLDivElement
/**
* The settings
*/
public readonly settings: Settings
/**
* The background of main layer that contains image and overlay
*
* @remark
* Background component is a not selectable shape that represents Image and Rect nodes.
* The nodes are accessible with `background.image` and `background.overlay` APIs
* @see [[https://konvajs.org/api/Konva.Image.html | Image]] and [[ https://konvajs.org/api/Konva.Rect.html | Rect]]
*
* @example
* ```ts
* editor.board.background.setImageFromUrl('<url>')
* ```
*
* @example
* ```ts
* editor.board.background.fill('rgba(0, 0, 0, 0.5)')
* ```
*
* @example
* ```ts
* editor.board.background.filter({
* name: 'Blur',
* options: {
* blurRadius: 20
* }
* })
* ```
*/
public readonly background: Background
/**
* The selection manager components that lets select and manage shapes with UI or API
*
* @example
* Selects all shapes
* ```ts
* editor.board.selection.selectAll()
* ```
*
* @example
* Deselects all shapes
* ```ts
* editor.board.selection.deselectAll()
* ```
*/
public readonly selection: Selection
/**
* Demonstrates the current active drawing. it's a string value or `null`.
*
* This property is managing by [[ShapeDrawer]] directly
*/
public activeDrawing: string | null = null
/**
* @see [[Events]]
*/
public readonly events: Events
/**
* @see [[History]]
*/
public readonly history: History
/**
* The array that contains all created shapes including active and deleted items. this property is managing by [[ShapeDrawer]] and [[Selection]]
*
* @see [[Board.addShape]] and [[Board.setShapes]]
*
*/
private shapesList: Array<ShapeModel> = []
/**
* Creates a new stage, layer, background and selection instance
*
* @param settings The [[Settings]]
* @param events The [[Events]]
* @param history The [[History]]
*/
constructor(settings: Settings, events: Events, history: History) {
this.settings = settings
this.history = history
this.events = events
const width = this.settings.width || this.settings.container.clientWidth
const height = this.settings.height || this.settings.container.clientHeight
this.stage = new Konva.Stage({
container: this.settings.container,
width,
height
})
// rename class name
this.stage.content.className = this.settings.containerClassName!
// set container position to center-center
Object.assign(this.stage.content.style, {
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%,-50%)'
})
this.stage.on('widthChange', this.rescale.bind(this))
this.stage.on('heightChange', this.rescale.bind(this))
// disable context menu
if (this.settings.disableCanvasContextMenu) {
this.settings.container.addEventListener('contextmenu', (e: MouseEvent) =>
e.preventDefault()
)
}
this.layer = new Konva.Layer()
this.stage.add(this.layer)
this.background = new Background(this)
this.selection = new Selection(this)
this.container = this.settings.container
}
/**
* Calculates the board dimensions based on different components
*
* @returns [[Dimension]]
*/
public getDimensions() {
return {
width:
this.background.image.node.width() ||
this.background.overlay.node.width() ||
this.stage.width() ||
this.settings.width!,
height:
this.background.image.node.height() ||
this.background.overlay.node.height() ||
this.stage.height() ||
this.settings.height!
}
}
/**
* Returns all nodes in the main layer including background nodes
*
* @returns array of [[ShapeModel.node]]
*/
public getNodes() {
return [
...this.background.nodes,
...this.shapesList.map(shape => shape.node)
]
}
/**
* Returns all created shapes
*
* @see [[ShapeModel]]
*/
public get shapes() {
return this.shapesList
}
/**
* Returns all created shapes except deleted and hidden shpaes
*
* @see [[ShapeModel]]
*/
public get activeShapes() {
return this.shapesList.filter(shape => shape.isActive)
}
/**
* Add a new shape to the list of the shapes
*/
public addShape(shape: ShapeModel) {
this.shapesList.push(shape)
}
/**
* Updates list of the shapes
*/
public setShapes(shapes: ShapeModel[]) {
this.shapesList = shapes
}
/**
* Rescales the container based on its width and height
*/
public rescale() {
const transform = this.getContainerTransform()
if (this.stage.content.style.transform === transform) {
return
}
this.stage.content.style.transform = transform
this.events.emit('board:rescale', {
data: {
transform
}
})
}
/**
* Changes the active drawing mode
*
* @param drawType The drawing type string
*/
public setActiveDrawing(drawType: string | null) {
if (drawType) {
this.selection.transformer.hide()
this.draw()
}
if (drawType !== this.activeDrawing) {
this.events.emit('board:change-active-drawing', {
data: {
type: drawType
}
})
}
this.activeDrawing = drawType
}
/**
* Calculates the CSS transformations of board based on stage width and height
*
* @returns transform style of the container
*/
public getContainerTransform() {
const size = this.getDimensions()
let scale =
this.container.clientWidth < this.container.clientHeight
? this.stage.width() / size.width
: this.stage.height() / size.height
if (scale * this.stage.width() > this.container.clientWidth) {
scale = this.container.clientWidth / this.stage.width()
}
if (scale * this.stage.height() > this.container.clientHeight) {
scale = this.container.clientHeight / this.stage.height()
}
return `translate(-50%, -50%) scale(${scale.toFixed(6)})`
}
/**
* Redraws the main layer
*/
public draw() {
this.layer.batchDraw()
}

Grouping feature

Having the ability to group is a necessity. Konva suggests having fewer layers, whereas Pikaso offers only one. This means managing shapes through Groups is required.

I have drafted an API in my mind (it might change)

Board class will offer a groups field that is probably created from GroupManager

so editor.board.groups.list will provide list of the created groups, for example.
editor.board.groups.create('<name>') or editor.board.groups.remove('<name>') will create and remove groups.

ShapeModel#setGroup has to manage it for created shapes. Probably, it will have to create the group automatically if it doesn't exist and move it to another group if necessary.

Selecting label causes the shapes underneath to be selected

When the users moves a label on top of an existing shape, mouse events seems to be propagating to the underlying shape. Backspace keystroke used to edit the inline text will cause the shape beneath it to be deleted accidentally.

Steps to Reproduce

In the demo, https://pikaso.netlify.app/

  1. move the "Try Picaso!" on top of the image of the chin scratching couple
  2. double click the label to try to enter inline edit mode (it actually takes two consequtive double clicks to enter that mode)
  3. you'll notice that the background image becomes selected
  4. The label does go into inline edit mode however, when you try to press backspace to delete a character from the "Try Pikaso!" label it actually deletes the image underneath it.

Possible Solution

  • I've forked the project and added e.cancelBubble = true in the inlineEdit function that's triggered on a dblclick. This does prevent the double click event from propagating.
  • However, subsequent single clicks to move the text cursor still need to stop from bubbling. I couldn't find a solution for that at the time of writing.

I want to create a shape inside another shape

i am creating a rect. of full with and height according to window/document.
now i have no space outside that rect. to draw an other one.
basically it will be like room and i will create multiple object like a new rect. or a line over it.
so in this case i want to know how could that be possible.
or
or
or there should be a way that a when you hover over an object selection cursor appears so it can be edited.
but cursor should only come when you click on any object not hovering over it.
when you click on object then you can resize that object.

Empower developers to maintain their own state representation

I am implementing a complex drawing solution using Pikaso. Unfortunately, there doesn't seem to be anyway to reflect the drawn elements in state outside of Pikaso's internal state.
I need to keep the newly drawn items' information in my own component's state, however, it seems that there is no way to currently do it except doing editor.export.toJSON() and picking the latest item from there.
In the product I'm building, something you have drawn right now can be deleted by someone else sharing your session in the next second (just like any collaborative editing apps). For this reason, I must always keep a "clone" of Pikaso state in memory.

One way to do this is to constantly do editor.export.toJSON() on each and every event that the user is doing like adding/editing/removing/showing/hiding any node.
Do you think that that's the "right" way to do it? I wonder if it's good for performance when it comes to a board that has too many items rendered.

Describe the solution you'd like

I'm not sure if this is a good solution but maybe it would be a good idea to make private nodeToObject property of JsonExport class to be available as a standalone function, so that one can use it to mutate their state on each board event (by making sure that every "create" results in adding nodeToObject(currentItem) to custom state.

react-konva makes it really easy to have React state representing the shapes and mapping over them to draw Canvas items. This ensures that if some outside event or service deletes an object from the react state list, the canvas automatically makes that Konva node disappear. Of course, I will develop the reconciling (adding/removing specific nodes based on outside events) myself in the product's business logic for Pikaso, but I only need your insight on what's the best way to maintain that state to begin with. That if exporting the whole board as JSON at every event is alright or should I be doing something else.

If there is a solution that you recommend which needs changes to Pikaso itself I would be happy to work on it.

Include zIndex data when exporting canvas to json

Is your feature request related to a problem? Please describe.
I am trying to use certain method for setting zIndex of shape.
Currently this feature is not available on pikaso, however Konva has that ability to set zIndex.
https://konvajs.org/docs/groups_and_layers/zIndex.html

Problem started when I created one editor with Image and Text on top of that. Later I exported JSON and when I import that JSON back into editor then sequence or zindex is lost, image always comes on top and text on bottom hiding behind it. Having an option to set specific z index will solve the issue.

Describe the solution you'd like
If there is a way to access the native Konva shape method then it could solve lot of issues.

Describe alternatives you've considered
If it is not possible then there should be specific way to set index of object.
Currently shape.node has index property however there is no way to change the index of objects if we want to move one on top of other.

Sveltekit - TypeError: canvas.createCanvas is not a function

I'm trying to use Pikaso with Sveltekit. I've tried several variations of the following but all generally result in the same error.

Any direction is greatly appreciated.

<script lang="ts">
    import Pikaso from 'pikaso'
    import { onMount } from 'svelte';
    let editor;

    onMount(async () => {

        let pikaso = new Pikaso({
        container: editor,
      });

      pikaso.shapes.polygon.insert({
        x: 250,
        y: 250,
        radius: 900,
        sides: 6,
        fill: "tomato",
      });
    });


    
</script>

<div bind:this={editor}>
   
</div>

Error

Uncaught (in promise) TypeError: canvas.createCanvas is not a function
    createCanvasElement index.all.js:10383
    Canvas$1 index.all.js:1614
    SceneCanvas index.all.js:1676
    _buildDOM index.all.js:4161
    Stage index.all.js:3615
    Board2 index.all.js:12137
    init index.all.js:14282
    Pikaso2 index.all.js:14219
    instance Canvas.svelte:8
    run index.mjs:18
    mount_component index.mjs:1802
    flush index.mjs:1067
    init index.mjs:1894
    Root root.svelte:920
    createProxiedComponent svelte-hooks.js:341
    ProxyComponent proxy.js:242
    Proxy<Root> proxy.js:349
    initialize start.js:702
    _hydrate start.js:1602
    start start.js:1639
    <anonymous> (index):230

NodeJS Env Support

Is your feature request related to a problem? Please describe.
I would like to implement NodeJS Environment support so that something like this can be implemented
https://github.com/konvajs/konva#4-nodejs-env

We are looking to generate the image dynamically by replacing certain tokens in JSON.
We would be generating canvas and drawings that would be exported as JSON later on.
Later on we could replace some placeholder texts in JSON file to generate the fully dynamic image using node js environment.

Describe the solution you'd like
Konva supports the stage creation in nodejs environment. It would be really nice to have something like that in Pikaso.
https://github.com/konvajs/konva#4-nodejs-env

Example code in Konva

const Konva = require('konva/cmj').default;
let fs = require('fs');

let jsonContent = fs.readFileSync(process.cwd() + "/stage.json").toString();
jsonContent = jsonContent.replace("{{first_name}}", "Hussain");

var stage = Konva.Node.create(jsonContent);

let base64Data = stage.toDataURL();
base64Data = base64Data.replace(/^data:image\/png;base64,/, "");
fs.writeFileSync(process.cwd() + "/stage.png", base64Data, 'base64');

test

Can the zoom function of the canvas be realized? When the mouse rolls over the canvas, the canvas can be enlarged or shrunk, and the user can see more clearly. I tried to control the canvas size using the wheel event on the listening stage, but the mouse shifted when the box was selected

[ Feature ] Global config

I think this is mandatory to provide a global config to be able config every minor detail like transformer shape, selection behavior, default colors and etc

Keyboard: Formal Keyboard API/Map

This is just an accessibility feature, though, low priority, it goes well with #28, so, I will add it for discussion.

We might need a formal keyboard api, that will help access all core functionalities via the Keyboard. Especially features like zoom in/out.

Currently, we can focus on generic keyboard shortcuts; avoiding mac shortcuts, and implementing

SHORTCUTS

Undo
Redo

Canvas
Zoom in
Zoom out
Zoom to actual size
Zoom to fit canvas

Layers
Duplicate layer
Constrain proportions

RESIZE LAYER
Delete Layer
Nudge position by 1px
Nudge position by 10px
Bring forward
Send backward

Import: Handles/Transformers are not available when imported from JSON

Text Label and Shapes seem to behave differently when created and when imported from JSON.

They cant be resized/transformed as the handles/transformers are missing.

Check in this demo: https://bnbear.bubbleapps.io/version-test/edit_template/temp1?project_id=1624555421210x555044648605350200 (Click on 'New Layer' to add a shape or text, and compare to shapes that exist on the canvas, loaded from JSON)

We may need an accessible way to switch this on/off, depending on use-case.

A suggestion to avoid canvas leak on iOS/Mac safari

When I was using Pikaso, I found a canvas leak problem on webbiew/safari of iOS and Safari of Mac and Windows. It's not a bug of Pikaso or Konva-JS, it may be an bad implementaion of iOS webview.
But using pikaso in some way will cause the canvas leak ,and reach the limi of 384M memory of iOS,then no canvas can be operated on the web page.
Let me describe the detail of the problem.

  1. Every konva stage and layer has two canvas. (https://konvajs.org/docs/how_it_works.html) Canvas of a stage can be accessed by stage.bufferCanvas._canvas and stage.bufferHitCanvas._canvas. Canvas of a Layer can be accessed by layer.canvas._canvas and layer.hitCanvas.
  2. When konvajs is running on iOS safari or MAC safari , any change of url will not cause the release of konva canvas. You can have a test on this, and the amount of canvas can be traced by safari inspector (the graphics module). So we need to release the canvas by setting the canvas width and height to 1.
  3. Pikaso has two processes that can cause konva stage clone, so we may also need to manually release canvas in these two process.
    (1) The loading process. The reset function will create a new konva stage, so the elder stage may need to be released manually

(2) The setImageFromUrl function. It will create a history state with a konva stage and a snapshot will be clone from the stage. The snapshot is a local variable, so the canvas of the snapshot will cause a leak.

Flip breaking when shape is rotated

Description:
Both Vertical and Horizontal Flip breaking when the Background Image or other shapes are rotated

Always Reproducible:
Yes

Version
1.0.0-beta.13

Browser
All browsers

Board: Zooming stage relative to pointer position/center

Currently as it is, the app developer is in-charge of the zooming functionality. Without the snap to grid/shape functionality, using the keyboard becomes the only option, while keeping track of the x and y variables.

I am not sure if we have a keyboard shortcut map, but that can also be added later.

As seen in this Konva.js demo.

In this functionality, we want the area around the canvas to be part of the <canvas/>, instead of the current <div>.

  • the current shape/board, or background image/overlay should lose focus/selection when i click outside the stage.
  • We can have a minimum/maximum zooming threshold.
  • We only support one stage/board at the moment, and its always the center of focus.
  • We add zooming functionality and a way of accessing the current zooming states
  • We add "Zoom To" functionality (Actual Size, Fit Canvas)

We can break down this to smaller issues, if we get to that point, or if this feature is within Pikaso's focus.

If we can have this feature, it would be easy to create a feature such as:

  • Zooming and Panning, which will add more functionality like Zoom to Selection, and Zoom to Stage/Board.

Import SvgModel, SvgDrawer

Can't import classes SvgModel & SvgDrawer

import { SvgDrawer, SvgModel } from 'pikaso';

My IDE automatically add these imports:
import { SvgDrawer } from 'pikaso/esm/shape/drawers/SvgDrawer'; import { SvgModel } from 'pikaso/esm/shape/models/SvgModel';

I got this error on compiling:
Module not found: Error: Can't resolve 'pikaso/esm/shape/drawers/SvgDrawer'

Maybe the SgvDrawer and SvgModel exports are missing in index.all.ts ?

Additional context
Use in Angular

Version
"pikaso": "^2.7.5"

Documentation: "How to Contribute" manual

Currently, there is no way for persons new to the TypeScript/Node.js/React.js ecosystem to setup/contribute.

We may need a policy on the following:

  • How to set up locally
  • Branch Organization
  • How to report Bugs
  • How to Get in Touch
  • How to propose a change/feature
  • How to send a pull a request
  • How to write tests/run tests
  • Development workflow

Image shapes cannot be created in NodeJs

Describe the bug
Create Image shape in NodeJs is not working
Reference Error: File is not defined

How To Reproduce

const { Pikaso } = require('pikaso')

const editor = new Pikaso({
  width: 500,
  height: 500
})

editor.shapes.image.insert('<url>')

Version
2.7.1

Shape: Default name of shape

I know we have discussed this is #24. But I feel that we should have default names for each shape created.

In #24 you had suggested that we should pass the name such as:

const rect = editor.shapes.rect.insert({
   name: '<name>',
   // rest config
})

and access that through console.log(rect.node.name()), or change the name through rect.node.name('<new name>')

I feel that this leaves room for bugs, due to missing this in Pikaso's documentation.

I suggest we add a method renameShape() and add

public insert(config: Konva.ArrowConfig): ArrowModel {
    return super.insert({
         name: `${type}`
         ...config
    })
}

and duplicate take the name of the original, and postfix -copy, e.g, triangle to triangle-copy.

Two shapes can have the same name however...

New center and zoom options

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
  })
}

Ability to resize Imported Image

Is your feature request related to a problem? Please describe.
Currently, when you load from an Image from a URL, the size of the image overrides all other settings of width and height. This breaks the UI, as the developer is forced to resize the image before importing it into Pikaso.

Describe the solution you'd like
If we can have the loadFromUrl or setImageFromUrl to accept a resize value, which can be a percentage of its aspect ratio, or actual width and height values that can be respected.

Describe alternatives you've considered

  • Resizing the image
  • Dynamically recalculate the image at runtime

The image imported should not be larger than scene area, unless explicitly zoomed.

Add destroy method to Pikaso instance

Is your feature request related to a problem? Please describe.
Need a way to destroy the Pikaso instance so that it no longer listens for events or any adjacent code

Describe the solution you'd like
In the main instance add a method called destroy similar to the one in KonvaJS

class Pikaso {
  constructor(config) {
    // constructor implementation
  }

  // other methods implementation

  destroy() {
    // stop listening to events
    this.off();

    // other cleanup operations
    // ...

    // set instance properties to null to aid garbage collection
    for (let prop in this) {
      if (this.hasOwnProperty(prop)) {
        this[prop] = null;
      }
    }
  }
}

Board: Duplicate Shape

There is no copy/paste functionality, but a duplicate shape feature would be nice to have.

  • On selection (on or more items), duplicate the shape, and lodge the x and y value of the duplicate, by a small offset (5px or 10px)
  • Each shape object can handle its own duplication
  • This functionality, can be exposed on the Board.
  • This can be done on a shape or group

Background Image and Overlay settings

Is your feature request related to a problem? Please describe.
Currently, once you have set the background items to be selectable;

editor.board.background.image.isSelectable = true;
editor.board.background.overlay.isSelectable = true;

There is no way of setting if the image is resizable or draggable on creation.

Describe the solution you'd like

  • The overlay and image should be grouped by default, and draggable & resizable together.
  • The overlay and image should not be able to resize/drag past the size of the board, unless the user wants that (advanced).
  • The image/overlay can be selectable and not draggable at the same time.

Describe alternatives you've considered

  • I have considered having this out of Pikaso, but its an important feature especially for graphic designers.

Additional context
https://codesandbox.io/s/59-ability-to-resize-imported-image-forked-idxry0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.