如何在 Konva js 舞台上处理图像(溢出、可拖动区域等)?
How to handle with images (overflow, draggable area, etc) on Konva js stage?
我正在尝试使用 konva.js 创建一个舞台。基本上,我需要根据一些布局在舞台上添加两个(至少)或更多图像。
示例:
我有一个布局,将舞台区域真实地分成两个相似的组。每组一张图片。
示例代码:
var stage = new Konva.Stage({
container: 'container',
width: width, // 295px
height: height, // 600px
});
var layer = new Konva.Layer({
imageSmoothingEnabled: true
});
// add a vertical line in order to show seperated groups
var line = new Konva.Line({
points: [stage.width() / 2, 0, stage.width() / 2, stage.height()],
stroke: '#9499a3',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
});
layer.add(line)
// create group #1
var group1 = new Konva.Group({
x: 0,
y: 0,
width: stage.width() / 2,
height: stage.height()
});
var image1;
var imageObj = new Image();
imageObj.onload = function () {
image1 = new Konva.Image({
x: (stage.width() / 2 - imageObj.width) - line.strokeWidth() / 2,
//y: 0,
width: imageObj.width,
height: stage.height(),
image: imageObj,
draggable: true,
});
//layer.add(image1);
group1.add(image1);
image1.on('dragstart', function () {
console.log('dragstart')
});
image1.on('dragmove', function(e){
console.log('X : ' + this.attrs.x + ', Y : ' + this.attrs.y)
});
image1.on('dragend', function () {
console.log('X : ' + this.attrs.x + ', Y : ' + this.attrs.y)
});
};
imageObj.src = 'img/1.jpg';
// create group #2
var group2 = new Konva.Group({
x: stage.width() / 2 + line.strokeWidth() / 2,
y: 0,
width: stage.width() / 2,
height: stage.height()
});
var image2;
var imageObj = new Image();
imageObj.onload = function () {
image2 = new Konva.Image({
//x: stage.width() / 2 + line.strokeWidth() / 2,
//y: stage.height() / 2 - imageObj.height / 2,
width: imageObj.width,
height: stage.height(),
image: imageObj,
draggable: true,
});
//layer.add(image2);
group2.add(image2);
};
imageObj.src = 'img/2.jpg';
layer.add(group1, group2)
stage.add(layer);
我想做的事情:
- 定义每个图像(或组)的可拖动区域,以免彼此之间溢出。
- 检查图层是否可见,以便重新定位图像以隐藏图层。
所以实现这一点的方法是用一个矩形定义图像将被约束的框架。将其放入一个组中,并设置该组的剪辑区域以匹配框架矩形的位置和大小。现在将图像添加到组中。只有组中的图像部分可见。
作为奖励,如果您将 dragBoundFunc 添加到组中,您可以确保不会将超大图像拖到框架边缘之外。
请参阅下面的代码片段(最佳 运行 full-screen)和可编辑的 CodePen here。
当然,这只是一个图像帧,您在其中描述了在您的用例中会说两个图像帧。我建议你解开代码然后制作一个class,然后你可以使用多少个等等
// this data gives the position and size of the frame
let data = {
frameGroup: { x: 50, y: 100, width: 800, height: 300, strokeWidth: 10, stroke: 'cyan'},
fadeImage: {opacity: 0.3}
}
// add a stage
let stage = new Konva.Stage({container: 'container', width: 1000, height: 500 }),
layer = new Konva.Layer({}), // Add a layer and group to draw on
group = new Konva.Group({clip: data.frameGroup}),
rect = new Konva.Rect(data.frameGroup),
image = new Konva.Image({draggable: true}),
fadeImage = null,
imageObj = new Image();
stage.add(layer);
layer.add(group)
group.add(rect);
rect.listening(false); // stop the frame rect intercepting events
// Use the html image object to load the image and handle when laoded.
imageObj.onload=function () {
image.image(imageObj); // set the Konva image content to the html image content
// compute image position so that it is initially centered in the frame
let imagePos = getMiddlePos(data.frameGroup, data.frameGroup, {width: imageObj.width, height: imageObj.height});
// set the Konva image attributes as needed
image.setAttrs({
x: imagePos.x, y: imagePos.y, width: imageObj.width, height: imageObj.height,
// This function ensures the oversized image cannot be dragged beyond frame edges.
// Is is firect by the drag event.
dragBoundFunc: function(pos){
var imagePos = this.getClientRect(); // get the image dimensions.
let
maxPos = { // compute max x & y position allowed for image
x: data.frameGroup.x,
y: data.frameGroup.y
},
minPos = {
x: data.frameGroup.x + data.frameGroup.width - imagePos.width,
y: data.frameGroup.y + data.frameGroup.height - imagePos.height
},
newX = (pos.x >= maxPos.x) ? maxPos.x : pos.x, // ensure left edge not within frame
newY = (pos.y >= maxPos.y) ? maxPos.y : pos.y; // ensure top edge not within frame
newX = newX < minPos.x ? minPos.x : newX; // ensure right edge not within frame
newY = newY < minPos.y ? minPos.y : newY; // ensure top edge not within frame
fadeImage.setAttrs({x: newX, y: newY}); // apply what we computed
// dragBoundFunc must return a value with x & y. Either return same value passed in
// or modify the value.
return {
x: newX,
y: newY
};
}
})
group.add(image) // add the image to the frame group
image.moveToBottom(); // ensure the frame rect is above the image in the z-index.
// make a clone of the image to be used as the fade image.
fadeImage = image.clone({draggable: false, opacity: data.fadeImage.opacity});
layer.add(fadeImage);
// ensure fade image is one step below the frame group. ! - in this simple demo Konva will raise
// a warning because group.zIndex() = 0.
fadeImage.zIndex(group.zIndex() - 1);
}
imageObj.src = "https://assets.codepen.io/255591/hubble_space_image.jpg?x=1"
// simple function to get the x & y for the image to be centered in the frame
function getMiddlePos(framePos, frameSize, imageSize){
return{
x: framePos.x + (frameSize.width - imageSize.width)/2,
y: framePos.y + (frameSize.height - imageSize.height)/2,
}
}
// Toggle use of fade image to show overflowed part of image.
$('#useFadImage').on('change', function(e){
if (fadeImage){
fadeImage.visible(!fadeImage.visible());
}
})
body {
margin: 14px;
padding: 10px;
font: 12pt Verdana, Arial, sans-serif;
}
#container {
width: 1000px;
height: 500px;
border: 1px solid red;
}
<p><h2>Constrain an image to the bounds of a frame</h2></p>
<p>1. Set the frame group clip region.</p>
<p>2. Set dragBounds function on the image so that it cannot escape the group.</p>
<p>Drag the image and note that it cannot me dragged such that white space in the frame would be visible.</p>
<p>
<input type='checkbox' id='useFadImage' checked='' /><label for="useFadImage">Use fade image - shows area of image outside the frame </label>
</p>
<div id='container' ></div>
<p>Image from <a href="https://www.nasa.gov/multimedia/imagegallery/iotd.html">NASA Image of the day.</a></p>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src="https://unpkg.com/konva@8/konva.min.js"></script>
有一篇关于主题 here 的博客条目。
我正在尝试使用 konva.js 创建一个舞台。基本上,我需要根据一些布局在舞台上添加两个(至少)或更多图像。
示例:
我有一个布局,将舞台区域真实地分成两个相似的组。每组一张图片。
示例代码:
var stage = new Konva.Stage({
container: 'container',
width: width, // 295px
height: height, // 600px
});
var layer = new Konva.Layer({
imageSmoothingEnabled: true
});
// add a vertical line in order to show seperated groups
var line = new Konva.Line({
points: [stage.width() / 2, 0, stage.width() / 2, stage.height()],
stroke: '#9499a3',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
});
layer.add(line)
// create group #1
var group1 = new Konva.Group({
x: 0,
y: 0,
width: stage.width() / 2,
height: stage.height()
});
var image1;
var imageObj = new Image();
imageObj.onload = function () {
image1 = new Konva.Image({
x: (stage.width() / 2 - imageObj.width) - line.strokeWidth() / 2,
//y: 0,
width: imageObj.width,
height: stage.height(),
image: imageObj,
draggable: true,
});
//layer.add(image1);
group1.add(image1);
image1.on('dragstart', function () {
console.log('dragstart')
});
image1.on('dragmove', function(e){
console.log('X : ' + this.attrs.x + ', Y : ' + this.attrs.y)
});
image1.on('dragend', function () {
console.log('X : ' + this.attrs.x + ', Y : ' + this.attrs.y)
});
};
imageObj.src = 'img/1.jpg';
// create group #2
var group2 = new Konva.Group({
x: stage.width() / 2 + line.strokeWidth() / 2,
y: 0,
width: stage.width() / 2,
height: stage.height()
});
var image2;
var imageObj = new Image();
imageObj.onload = function () {
image2 = new Konva.Image({
//x: stage.width() / 2 + line.strokeWidth() / 2,
//y: stage.height() / 2 - imageObj.height / 2,
width: imageObj.width,
height: stage.height(),
image: imageObj,
draggable: true,
});
//layer.add(image2);
group2.add(image2);
};
imageObj.src = 'img/2.jpg';
layer.add(group1, group2)
stage.add(layer);
我想做的事情:
- 定义每个图像(或组)的可拖动区域,以免彼此之间溢出。
- 检查图层是否可见,以便重新定位图像以隐藏图层。
所以实现这一点的方法是用一个矩形定义图像将被约束的框架。将其放入一个组中,并设置该组的剪辑区域以匹配框架矩形的位置和大小。现在将图像添加到组中。只有组中的图像部分可见。
作为奖励,如果您将 dragBoundFunc 添加到组中,您可以确保不会将超大图像拖到框架边缘之外。
请参阅下面的代码片段(最佳 运行 full-screen)和可编辑的 CodePen here。
当然,这只是一个图像帧,您在其中描述了在您的用例中会说两个图像帧。我建议你解开代码然后制作一个class,然后你可以使用多少个等等
// this data gives the position and size of the frame
let data = {
frameGroup: { x: 50, y: 100, width: 800, height: 300, strokeWidth: 10, stroke: 'cyan'},
fadeImage: {opacity: 0.3}
}
// add a stage
let stage = new Konva.Stage({container: 'container', width: 1000, height: 500 }),
layer = new Konva.Layer({}), // Add a layer and group to draw on
group = new Konva.Group({clip: data.frameGroup}),
rect = new Konva.Rect(data.frameGroup),
image = new Konva.Image({draggable: true}),
fadeImage = null,
imageObj = new Image();
stage.add(layer);
layer.add(group)
group.add(rect);
rect.listening(false); // stop the frame rect intercepting events
// Use the html image object to load the image and handle when laoded.
imageObj.onload=function () {
image.image(imageObj); // set the Konva image content to the html image content
// compute image position so that it is initially centered in the frame
let imagePos = getMiddlePos(data.frameGroup, data.frameGroup, {width: imageObj.width, height: imageObj.height});
// set the Konva image attributes as needed
image.setAttrs({
x: imagePos.x, y: imagePos.y, width: imageObj.width, height: imageObj.height,
// This function ensures the oversized image cannot be dragged beyond frame edges.
// Is is firect by the drag event.
dragBoundFunc: function(pos){
var imagePos = this.getClientRect(); // get the image dimensions.
let
maxPos = { // compute max x & y position allowed for image
x: data.frameGroup.x,
y: data.frameGroup.y
},
minPos = {
x: data.frameGroup.x + data.frameGroup.width - imagePos.width,
y: data.frameGroup.y + data.frameGroup.height - imagePos.height
},
newX = (pos.x >= maxPos.x) ? maxPos.x : pos.x, // ensure left edge not within frame
newY = (pos.y >= maxPos.y) ? maxPos.y : pos.y; // ensure top edge not within frame
newX = newX < minPos.x ? minPos.x : newX; // ensure right edge not within frame
newY = newY < minPos.y ? minPos.y : newY; // ensure top edge not within frame
fadeImage.setAttrs({x: newX, y: newY}); // apply what we computed
// dragBoundFunc must return a value with x & y. Either return same value passed in
// or modify the value.
return {
x: newX,
y: newY
};
}
})
group.add(image) // add the image to the frame group
image.moveToBottom(); // ensure the frame rect is above the image in the z-index.
// make a clone of the image to be used as the fade image.
fadeImage = image.clone({draggable: false, opacity: data.fadeImage.opacity});
layer.add(fadeImage);
// ensure fade image is one step below the frame group. ! - in this simple demo Konva will raise
// a warning because group.zIndex() = 0.
fadeImage.zIndex(group.zIndex() - 1);
}
imageObj.src = "https://assets.codepen.io/255591/hubble_space_image.jpg?x=1"
// simple function to get the x & y for the image to be centered in the frame
function getMiddlePos(framePos, frameSize, imageSize){
return{
x: framePos.x + (frameSize.width - imageSize.width)/2,
y: framePos.y + (frameSize.height - imageSize.height)/2,
}
}
// Toggle use of fade image to show overflowed part of image.
$('#useFadImage').on('change', function(e){
if (fadeImage){
fadeImage.visible(!fadeImage.visible());
}
})
body {
margin: 14px;
padding: 10px;
font: 12pt Verdana, Arial, sans-serif;
}
#container {
width: 1000px;
height: 500px;
border: 1px solid red;
}
<p><h2>Constrain an image to the bounds of a frame</h2></p>
<p>1. Set the frame group clip region.</p>
<p>2. Set dragBounds function on the image so that it cannot escape the group.</p>
<p>Drag the image and note that it cannot me dragged such that white space in the frame would be visible.</p>
<p>
<input type='checkbox' id='useFadImage' checked='' /><label for="useFadImage">Use fade image - shows area of image outside the frame </label>
</p>
<div id='container' ></div>
<p>Image from <a href="https://www.nasa.gov/multimedia/imagegallery/iotd.html">NASA Image of the day.</a></p>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src="https://unpkg.com/konva@8/konva.min.js"></script>
有一篇关于主题 here 的博客条目。