I have below code which will draw rectangle when user press "Shift + Left Mouse Click"
// Draw text box with alt + mouse left click
docViewer.on('click', (evt: any) => {
if (evt.shiftKey) {
// Get get window coordinates
const windowCoords = getMouseLocation(evt);
// Get current page number
const displayMode = docViewer.getDisplayModeManager().getDisplayMode();
const page = displayMode.getSelectedPages(windowCoords, windowCoords);
const clickedPage = (page.first !== null) ? page.first : docViewer.getCurrentPage();
// Get page coordinates
const pageCoordinates = displayMode.windowToPage(windowCoords, clickedPage);
// create rectangle
const rectangleAnnot = new instanceAnnotations.RectangleAnnotation();
rectangleAnnot.PageNumber = clickedPage + 1;
rectangleAnnot.X = pageCoordinates.x;
rectangleAnnot.Y = pageCoordinates.y - 14;
rectangleAnnot.Width = 200;
rectangleAnnot.Height = 14;
rectangleAnnot.StrokeColor = new instanceAnnotations.Color(255, 0, 0, 1);
rectangleAnnot.StrokeThickness = 2;
rectangleAnnot.Author = annotManager.getCurrentUser();
annotManager.addAnnotation(rectangleAnnot, false);
annotManager.redrawAnnotation(rectangleAnnot);
}
});
Now the issue is above code draw rectangle fine if PDF is vertical but if PDF is Horizontal then it draw Rectangle vertically. Please check below screenshot for reference.
As you can see on Page 1 it draws vertical box but on 2nd page its draws fine.
So how one can resolve it?
You need to account for page rotation to ensure your rect is aligned with the page.
Here is a quick example of how you can achieve that using the getCompleteRotation API, by setting width and height depending on the document rotation.
docViewer.on("click", (evt) => {
if (evt.shiftKey) {
// Get get window coordinates
const windowCoords = getMouseLocation(evt);
// Get current page number
const displayMode = docViewer.getDisplayModeManager().getDisplayMode();
const page = displayMode.getSelectedPages(windowCoords, windowCoords);
const clickedPage =
page.first !== null ? page.first : docViewer.getCurrentPage();
// Get page coordinates
const pageCoordinates = displayMode.windowToPage(
windowCoords,
clickedPage
);
// create rectangle
const rectangleAnnot = new Annotations.RectangleAnnotation();
rectangleAnnot.PageNumber = clickedPage + 1;
// Depending on doc orientation set Width and Height
const rotation = docViewer.getCompleteRotation(clickedPage);
const widthAndHeight = getWidthAndHeightBasedOnRotation(rotation);
// You will have to adjust the X, Y as well depending on rotation
rectangleAnnot.X = pageCoordinates.x;
rectangleAnnot.Y = pageCoordinates.y;
rectangleAnnot.Width = widthAndHeight.width;
rectangleAnnot.Height = widthAndHeight.height;
rectangleAnnot.StrokeColor = new Annotations.Color(255, 0, 0, 1);
rectangleAnnot.StrokeThickness = 2;
rectangleAnnot.Author = annotManager.getCurrentUser();
annotManager.addAnnotation(rectangleAnnot, false);
annotManager.redrawAnnotation(rectangleAnnot);
}});
const getWidthAndHeightBasedOnRotation = (rotation) => {
switch (rotation) {
case CoreControls.PageRotation["E_0"]:
return {
width: 200,
height: 14,
};
case CoreControls.PageRotation["E_90"]:
return {
width: 14,
height: 200,
};
case CoreControls.PageRotation["E_180"]:
return {
width: 200,
height: 14,
};
case CoreControls.PageRotation["E_270"]:
return {
width: 14,
height: 200,
};
}
};
You can access the CoreControls object from the instance. Please note that you will also need to tweak your X,Y coordinates based on the rotation. This is a good resource on PDF coordinates and viewer coordinates to help you wrap your head around that part.
Related
I am quite new to javascript, and I have been following tutorials at https://konvajs.org/ to help me learn their library.
I am currently trying to make it so you can load and select local images to move, resize, and rotate them.
This is the code I have so far:
<head>
<!-- USE DEVELOPMENT VERSION -->
<script src="https://unpkg.com/konva#7.0.0/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Select and Transform Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/3.2.5/konva.min.js"></script>
<div>Render a local image without upload</div>
<div>
<input type="file" id="file_input">
</div>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
stage.add(layer);
//add images
// listen for the file input change event and load the image.
$("#file_input").change(function(e){
var URL = window.webkitURL || window.URL;
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.src = url;
img.onload = function() {
var img_width = img.width;
var img_height = img.height;
// calculate dimensions to get max 300px
var max = 300;
var ratio = (img_width > img_height ? (img_width / max) : (img_height / max))
// now load the Konva image
var theImg = new Konva.Image({
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
layer.add(theImg);
layer.draw();
}
});
var tr = new Konva.Transformer();
layer.add(tr);
// by default select all shapes
// at this point basic demo is finished!!
// we just have several transforming nodes
layer.draw();
// add a new feature, lets add ability to draw selection rectangle
var selectionRectangle = new Konva.Rect({
fill: 'rgba(0,0,255,0.5)',
});
layer.add(selectionRectangle);
var x1, y1, x2, y2;
stage.on('mousedown touchstart', (e) => {
// do nothing if we mousedown on eny shape
if (e.target !== stage) {
return;
}
x1 = stage.getPointerPosition().x;
y1 = stage.getPointerPosition().y;
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.visible(true);
selectionRectangle.width(0);
selectionRectangle.height(0);
layer.draw();
});
stage.on('mousemove touchmove', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.setAttrs({
x: Math.min(x1, x2),
y: Math.min(y1, y2),
width: Math.abs(x2 - x1),
height: Math.abs(y2 - y1),
});
layer.batchDraw();
});
stage.on('mouseup touchend', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
// update visibility in timeout, so we can check it in click event
setTimeout(() => {
selectionRectangle.visible(false);
layer.batchDraw();
});
var shapes = stage.find('.rect').toArray();
var box = selectionRectangle.getClientRect();
var selected = shapes.filter((shape) =>
Konva.Util.haveIntersection(box, shape.getClientRect())
);
tr.nodes(selected);
layer.batchDraw();
});
// clicks should select/deselect shapes
stage.on('click tap', function (e) {
// if we are selecting with rect, do nothing
if (selectionRectangle.visible()) {
return;
}
// if click on empty area - remove all selections
if (e.target === stage) {
tr.nodes([]);
layer.draw();
return;
}
// do nothing if clicked NOT on our rectangles
if (!e.target.hasName('rect')) {
return;
}
// do we pressed shift or ctrl?
const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
const isSelected = tr.nodes().indexOf(e.target) >= 0;
if (!metaPressed && !isSelected) {
// if no key pressed and the node is not selected
// select just one
tr.nodes([e.target]);
} else if (metaPressed && isSelected) {
// if we pressed keys and node was selected
// we need to remove it from selection:
const nodes = tr.nodes().slice(); // use slice to have new copy of array
// remove node from array
nodes.splice(nodes.indexOf(e.target), 1);
tr.nodes(nodes);
} else if (metaPressed && !isSelected) {
// add the node into selection
const nodes = tr.nodes().concat([e.target]);
tr.nodes(nodes);
}
layer.draw();
});
</script>
Demo: https://www.w3schools.com/code/tryit.asp?filename=GG5QCXFMLFXJ
I am unsure how to make the selecting work on images, rather than rectangles.
Thank you
In the demo, you will see that "rect" names is used to detect selectable shapes. That is a useful approach, because you may have non-selectable shapes on the stage (like a background).
So to check a shape if it is selectable, we use:
e.target.hasName('rect')
So just remember to add "rect" name to new images on the stage:
// now load the Konva image
var theImg = new Konva.Image({
name: 'rect',
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
The name itself is not very important. You can find a different way to detect "selectable" nodes.
https://www.w3schools.com/code/tryit.asp?filename=GG6XVLB39IKW
I am trying to replicate the same result as using CSS width: 50vw; and height: 100vh; but in Javascript. My code is not currently creating the desired effect.
const logicalWidth = window.innerWidth / 2;
const logicalHeight = window.innerHeight;
I can see there will be some issues down the line with making this responsive as it will be full-width on ipad/ mobile. What I'm thinking might be the best way to handle this is rendering the image using CSS background-image: and this way I can control width, height and background-position with media query
I tried this but it does not work
.js-canvas {
background-image: url('https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg');
width: 50vw;
height: 100%;
background-position: center center;
}
Can anyone suggest a solution to this? Very happy to do this all with JS but not sure where to begin
// Declare all vars
let bgSprite,
displacementSprite,
displacementFilter,
pointerSprite,
pointerFilter;
// Images used
const images = [
{
name: 'bg',
url: 'https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg'
},
{
name: 'clouds',
url: 'https://raw.githubusercontent.com/pixijs/examples/gh-pages/examples/assets/pixi-filters/displacement_map_repeat.jpg'
}
];
const logicalWidth = 1800;
const logicalHeight = 1080;
// Determine & create the PIXI App instance
const canvasEl = document.querySelector('.js-canvas');
const canvasElOptions = {
autoDensity: true,
backgroundColor: 0xFFFFFF,
resizeTo: window,
resolution: window.devicePixelRatio || 1,
view: canvasEl
};
const resizeHandler = () => {
const scaleFactor = Math.min(
window.innerWidth / logicalWidth,
window.innerHeight / logicalHeight
);
const newWidth = Math.ceil(logicalWidth * scaleFactor);
const newHeight = Math.ceil(logicalHeight * scaleFactor);
app.renderer.view.style.width = `${newWidth}px`;
app.renderer.view.style.height = `${newHeight}px`;
app.renderer.resize(newWidth, newHeight);
mainContainer.scale.set(scaleFactor);
};
let app = new PIXI.Application(canvasElOptions);
let mainContainer = new PIXI.Container();
app.loader
.add(images)
.on('progress', loadProgressHandler)
.load(setup);
app.renderer.plugins.interaction.moveWhenInside = true;
function loadProgressHandler(loader, resource) {
//Display the percentage of files currently loaded
console.log("progress: " + loader.progress + "%");
//If you gave your files names as the first argument
//of the `add` method, you can access them like this
console.log("loading: " + resource.name);
}
function setup(loader, resources){
console.log("All files loaded");
resizeHandler();
app.stage.addChild(mainContainer);
window.addEventListener('resize', resizeHandler);
bgSprite = new PIXI.Sprite(resources.bg.texture);
bgSprite.interactive = true;
displacementSprite = new PIXI.Sprite(resources.clouds.texture);
// Make sure the sprite is wrapping.
displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
displacementFilter = new PIXI.filters.DisplacementFilter(displacementSprite);
pointerSprite = new PIXI.Sprite(resources.clouds.texture);
pointerFilter = new PIXI.filters.DisplacementFilter(pointerSprite);
displacementSprite.width = bgSprite.height;
displacementSprite.height = bgSprite.height;
pointerSprite.anchor.set(0.5);
pointerFilter.scale.x = 7;
pointerFilter.scale.y = 7;
mainContainer.addChild(bgSprite);
mainContainer.addChild(displacementSprite);
mainContainer.addChild(pointerSprite);
mainContainer.filters = [displacementFilter, pointerFilter];
pointerSprite.visible = false;
app.ticker.add((delta) => {
// Offset the sprite position to make vFilterCoord update to larger value.
// Repeat wrapping makes sure there's still pixels on the coordinates.
displacementSprite.x += 3.5 * delta;
displacementSprite.y += 3.5 * delta;
// Reset x & y to 0 when x > width to keep values from going to very huge numbers.
if (displacementSprite.x > displacementSprite.width) {
displacementSprite.x = 0;
displacementSprite.y = 0;
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.3/pixi.min.js"></script>
<canvas class="test js-canvas"></canvas>
I want this type of globe and I am using planetaryjs for this.
I have added the necessary resources for that in external resources link
including all js files and data file.
why the globe is not loading?
jsfiddle link
(function() {
var canvas = document.getElementById('quakeCanvas');
// Create our Planetary.js planet and set some initial values;
// we use several custom plugins, defined at the bottom of the file
var planet = planetaryjs.planet();
planet.loadPlugin(autocenter({extraHeight: -120}));
planet.loadPlugin(autoscale({extraHeight: -120}));
planet.loadPlugin(planetaryjs.plugins.earth({
topojson: { file: '/world-110m.json' },
oceans: { fill: '#001320' },
land: { fill: '#06304e' },
borders: { stroke: '#001320' }
}));
planet.loadPlugin(planetaryjs.plugins.pings());
planet.loadPlugin(planetaryjs.plugins.zoom({
scaleExtent: [50, 5000]
}));
planet.loadPlugin(planetaryjs.plugins.drag({
onDragStart: function() {
this.plugins.autorotate.pause();
},
onDragEnd: function() {
this.plugins.autorotate.resume();
}
}));
planet.loadPlugin(autorotate(5));
planet.projection.rotate([100, -10, 0]);
planet.draw(canvas);
// Create a color scale for the various earthquake magnitudes; the
// minimum magnitude in our data set is 2.5.
var colors = d3.scale.pow()
.exponent(3)
.domain([2, 4, 6, 8, 10])
.range(['white', 'yellow', 'orange', 'red', 'purple']);
// Also create a scale for mapping magnitudes to ping angle sizes
var angles = d3.scale.pow()
.exponent(3)
.domain([2.5, 10])
.range([0.5, 15]);
// And finally, a scale for mapping magnitudes to ping TTLs
var ttls = d3.scale.pow()
.exponent(3)
.domain([2.5, 10])
.range([2000, 5000]);
// Create a key to show the magnitudes and their colors
d3.select('#magnitudes').selectAll('li')
.data(colors.ticks(9))
.enter()
.append('li')
.style('color', colors)
.text(function(d) {
return "Magnitude " + d;
});
// Load our earthquake data and set up the controls.
// The data consists of an array of objects in the following format:
// {
// mag: magnitude_of_quake
// lng: longitude_coordinates
// lat: latitude_coordinates
// time: timestamp_of_quake
// }
// The data is ordered, with the earliest data being the first in the file.
d3.json('/examples/quake/year_quakes_small.json', function(err, data) {
if (err) {
alert("Problem loading the quake data.");
return;
}
var start = parseInt(data[0].time, 10);
var end = parseInt(data[data.length - 1].time, 10);
var currentTime = start;
var lastTick = new Date().getTime();
var updateDate = function() {
d3.select('#date').text(moment(currentTime).utc().format("MMM DD YYYY HH:mm UTC"));
};
// A scale that maps a percentage of playback to a time
// from the data; for example, `50` would map to the halfway
// mark between the first and last items in our data array.
var percentToDate = d3.scale.linear()
.domain([0, 100])
.range([start, end]);
// A scale that maps real time passage to data playback time.
// 12 minutes of real time maps to the entirety of the
// timespan covered by the data.
var realToData = d3.scale.linear()
.domain([0, 1000 * 60 * 12])
.range([0, end - start]);
var paused = false;
// Pause playback and update the time display
// while scrubbing using the range input.
d3.select('#slider')
.on('change', function(d) {
currentTime = percentToDate(d3.event.target.value);
updateDate();
})
.call(d3.behavior.drag()
.on('dragstart', function() {
paused = true;
})
.on('dragend', function() {
paused = false;
})
);
// The main playback loop; for each tick, we'll see how much
// time passed in our accelerated playback reel and find all
// the earthquakes that happened in that timespan, adding
// them to the globe with a color and angle relative to their magnitudes.
d3.timer(function() {
var now = new Date().getTime();
if (paused) {
lastTick = now;
return;
}
var realDelta = now - lastTick;
// Avoid switching back to the window only to see thousands of pings;
// if it's been more than 500 milliseconds since we've updated playback,
// we'll just set the value to 500 milliseconds.
if (realDelta > 500) realDelta = 500;
var dataDelta = realToData(realDelta);
var toPing = data.filter(function(d) {
return d.time > currentTime && d.time <= currentTime + dataDelta;
});
for (var i = 0; i < toPing.length; i++) {
var ping = toPing[i];
planet.plugins.pings.add(ping.lng, ping.lat, {
// Here we use the `angles` and `colors` scales we built earlier
// to convert magnitudes to appropriate angles and colors.
angle: angles(ping.mag),
color: colors(ping.mag),
ttl: ttls(ping.mag)
});
}
currentTime += dataDelta;
if (currentTime > end) currentTime = start;
updateDate();
d3.select('#slider').property('value', percentToDate.invert(currentTime));
lastTick = now;
});
});
// Plugin to resize the canvas to fill the window and to
// automatically center the planet when the window size changes
function autocenter(options) {
options = options || {};
var needsCentering = false;
var globe = null;
var resize = function() {
var width = window.innerWidth + (options.extraWidth || 0);
var height = window.innerHeight + (options.extraHeight || 0);
globe.canvas.width = width;
globe.canvas.height = height;
globe.projection.translate([width / 2, height / 2]);
};
return function(planet) {
globe = planet;
planet.onInit(function() {
needsCentering = true;
d3.select(window).on('resize', function() {
needsCentering = true;
});
});
planet.onDraw(function() {
if (needsCentering) { resize(); needsCentering = false; }
});
};
};
// Plugin to automatically scale the planet's projection based
// on the window size when the planet is initialized
function autoscale(options) {
options = options || {};
return function(planet) {
planet.onInit(function() {
var width = window.innerWidth + (options.extraWidth || 0);
var height = window.innerHeight + (options.extraHeight || 0);
planet.projection.scale(Math.min(width, height) / 2);
});
};
};
// Plugin to automatically rotate the globe around its vertical
// axis a configured number of degrees every second.
function autorotate(degPerSec) {
return function(planet) {
var lastTick = null;
var paused = false;
planet.plugins.autorotate = {
pause: function() { paused = true; },
resume: function() { paused = false; }
};
planet.onDraw(function() {
if (paused || !lastTick) {
lastTick = new Date();
} else {
var now = new Date();
var delta = now - lastTick;
var rotation = planet.projection.rotate();
rotation[0] += degPerSec * delta / 1000;
if (rotation[0] >= 180) rotation[0] -= 360;
planet.projection.rotate(rotation);
lastTick = now;
}
});
};
};
})();
Your globe is not loading for multiple reasons. First, if you open up your console you would see that the external resources were not loaded properly. As the error notes, your external resources failed to load because:
MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
You could overcome this issue in a twofold manner. You could either refer to this answer--which will help you sort the MIME type issue--or you may just use other links for you external resources. If you rather take the second route, you should add the links below to your external resources section, in the following order:
moment.js
d3.js
planetary.js
After you solved the first issue, you will see that you would not be able to link your JSON file by simply adding it to your external resources. These answers will offer you multiple approaches that will help you solve the JSON issue as well.
After you have successfully linked all of your external files, you will face a third problem. If you look at your code you will see that you are trying to get the time property for your data (JSON) object in line 75--var start = parseInt(data[0].time, 10);. However, as far as I could tell, your data object does not hold a time property--go ahead, and console.log() your data object to see its structure and properties. In other words, you might want to double check if the world-110m.json is the file that you want to work with.
Hope this helps.
I have a fabricjs canvas that I need to be able to zoom in and out and also change the image/object inside several times.
For this I setup the canvas in the first time the page loads like this:
fabric.Object.prototype.hasBorders = false;
fabric.Object.prototype.hasControls = false;
canvas = new fabric.Canvas('my_canvas', {renderOnAddRemove: false, stateful: false});
canvas.defaultCursor = "pointer";
canvas.backgroundImageStretch = false;
canvas.selection = false;
canvas.clear();
var image = document.getElementById('my_image');
if (image != null) {
imageSrc = image.src;
if(imageSrc.length > 0){
fabric.Image.fromURL(imageSrc, function(img) {
img = scaleImage(canvas, img); //shrinks the image to fit the canvas
img.selectable = false;
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
});
}
}
canvas.deactivateAll().renderAll();
Then when I need to change the image/object in the canvas or when the page reloads, I try to reset the canvas like this:
canvas.clear();
canvas.remove(canvas.getActiveObject());
var image = document.getElementById('my_image');
if (image != null) {
imageSrc = image.src;
if(imageSrc.length > 0){
fabric.Image.fromURL(imageSrc, function(img) {
img = scaleImage(canvas, img); //shrinks the image to fit the canvas
img.selectable = false;
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
});
}
}
Not sure if it matters but the way I change the image is by changing the source in 'my_image' and reseting the canvas with the above method.
This works well until I use canvas.zoomToPoint, as per this thread, after this, the image/object starts changing position when I reset the zoom or click the canvas with the mouse while it is zoomed, seeming to jump at each change in the top left corner direction, eventually disappearing from view.
Reset Zoom:
canvas.setZoom(1);
resetCanvas(); //(above method)
How can I restore the image/object position?
I tried doing the initial setup instead of the reset and seamed to work visually but was in fact adding a new layer of upper canvas at each new setup so it is no good.
Is there a way to reset the canvas to original state without causing this behavior and still be able to zoom in/out correctly?
Although this question is very old, here is what I did using the current version of fabric.js 2.2.4:
canvas.setViewportTransform([1,0,0,1,0,0]);
For your information: zooming to a point is a recalculation of the viewport transformation. The upper matrix is this is the initial viewport transform matrix.
I eventually fixed the problems I was having.
To reset the zoom, instead of just setting the zoom to 1 with canvas.setZoom(1), I reapplied the canvas.zoomToPoint method to the same point but with zoom 1, to force the initial zoom but regarding the same point that was used to zoom in.
As for the problem of restoring the image position in canvas (after panning for instance) it is as simple as removing the image, centering it in the canvas and re-adding it to the canvas as was done when adding first time:
var img = canvas.getActiveObject();
canvas.remove(img);
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
canvas.renderAll();
See below snippet - here I do the same - zooming together, but degrouping the objects in case somebody clicks on it.
The problem to get to original object properties can be solved, ungrouping the group and creating copies of them and reattaching - a bit annoying, but the only solution I found.
<script id="main">
// canvas and office background
var mainGroup;
var canvas = this.__canvas = new fabric.Canvas('c');
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
createOnjects(canvas);
// events - zoom
$(canvas.wrapperEl).on('mousewheel', function(e) {
var target = canvas.findTarget(e);
var delta = e.originalEvent.wheelDelta / 5000;
if (target) {
target.scaleX += delta;
target.scaleY += delta;
// constrain
if (target.scaleX < 0.1) {
target.scaleX = 0.1;
target.scaleY = 0.1;
}
// constrain
if (target.scaleX > 10) {
target.scaleX = 10;
target.scaleY = 10;
}
target.setCoords();
canvas.renderAll();
return false;
}
});
// mouse down
canvas.on('mouse:up', function(options) {
if (options.target) {
var thisTarget = options.target;
var mousePos = canvas.getPointer(options.e);
if (thisTarget.isType('group')) {
// unGroup
console.log(mousePos);
var clone = thisTarget._objects.slice(0);
thisTarget._restoreObjectsState();
for (var i = 0; i < thisTarget._objects.length; i++) {
var o = thisTarget._objects[i];
if (o._element.alt == "officeFloor")
continue;
else {
if (mousePos.x >= o.originalLeft - o.currentWidth / 2 && mousePos.x <= o.originalLeft + o.currentWidth / 2
&& mousePos.y >= o.originalTop - o.currentHeight / 2 && mousePos.y <= o.originalTop + o.currentHeight / 2)
console.log(o._element.alt);
}
}
// remove all objects and re-render
canvas.remove(thisTarget);
canvas.clear().renderAll();
var group = new fabric.Group();
for (var i = 0; i < clone.length; i++) {
group.addWithUpdate(clone[i]);
}
canvas.add(group);
canvas.renderAll();
}
}
});
// functions
function createOnjects(canvas) {
// ToDo: jQuery.parseJSON() for config file (or web service)
fabric.Image.fromURL('pics/OfficeFloor.jpg', function(img) {
var back = img.set({ left: 100, top: 100 });
back._element.alt = "officeFloor";
back.hasControls = false;
fabric.Image.fromURL('pics/me.png', function(img) {
var me = img.set({ left: -420, top: 275 });
me._element.alt = "me";
console.log(me);
var group = new fabric.Group([ back, me], { left: 700, top: 400, hasControls: false });
canvas.clear().renderAll();
canvas.add(group);
// remove all objects and re-render
});
});
}
</script>
I have a canvas draw feature:
var sketcher = null;
var brush = null;
$(document).ready(function(e) {
brush = new Image();
brush.src = 'assets/brush2.png';
brush.onload = function(){
sketcher = new Sketcher( "sketch", brush );
}
});
That uses sketcher.js. This allows the user to stamp a pattern depending on what brush pattern is used.
I want to be able to save the users click positions to localstorage and recall them if possible.
Here is the positions I want to save on the image below you can see the orangey/yellow dots that a user has clicked. I want to be able to save them out and recall them.
Here's my dirty attempt, you'll have to clean it up a little bit:
http://jsfiddle.net/ACt6v/2/
var canvas = document.getElementById("the-canvas");
var ctx = canvas.getContext("2d");
var clicks = [];
var localStorageEnabled = typeof(Storage);
var loadLink = document.getElementById("load");
canvas.onmousedown = function(e) {
clicks.push({
x: e.clientX,
y: e.clientY
})
ctx.fillStyle="blue";
ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10);
if( localStorageEnabled !=="undefined" ) {
localStorage["clicks"] = JSON.stringify(clicks);
}
}
loadLink.onmousedown = function(e) {
e.preventDefault();
console.log(localStorage["clicks"]); //view the console to see the clicks
var readClicks = JSON.parse(localStorage["clicks"]);
for (var i = 0 ; i < readClicks.length ; i++) {
ctx.fillStyle="red";
ctx.fillRect(readClicks[i].x - 5, readClicks[i].y - 5, 10, 10);
}
}
basically you save an array as a json string which contains all the coordinates of the points. This requires that the user clicks to create the dots. If you need to find the dots dynamically you will need another clean canvas.