Как нарисовать кликабельную линию в PIXI.js, используя PIXI.Graphics?
Я получил следующий код:
const linksGraphics = new PIXI.Graphics();
const update = () => {
linksGraphics.clear();
linksGraphics.alpha = 1;
if (forceLinkActive) {
data.links.forEach(link => {
let { source, target } = link;
linksGraphics.lineStyle(2, 0x000000);
linksGraphics.moveTo(source.x, source.y);
linksGraphics.lineTo(target.x, target.y);
});
linksGraphics.endFill();
} }
app.ticker.add( () => update() );
Где data.links - это массив граничных данных {источник: номер, цель: номер}. Если я правильно понимаю, все строки являются частью объекта PIXI.Graphics. Но что мне нужно
- каждая строка должна иметь свою непрозрачность
- каждая строка должна иметь событие для наведения мыши
Есть идеи, как изменить мой код?
Благодарю.
3 ответа
Вы можете определить hitArea на графике. А с помощью getBounds() вы можете сделать строку доступной для кликов. После того, как вы это сделаете, вы также можете присвоить графике pointerEvents.
const linksGraphics = new PIXI.Graphics();
const update = () => {
linksGraphics.clear();
linksGraphics.alpha = 1;
if (forceLinkActive) {
data.links.forEach(link => {
let { source, target } = link;
linksGraphics.lineStyle(2, 0x000000);
linksGraphics.moveTo(source.x, source.y);
linksGraphics.lineTo(target.x, target.y);
//A line itself is not clickable
linksGraphics.hitArea = linksGraphics.getBounds();
});
linksGraphics.endFill();
}
}
app.ticker.add( () => update() );
Прошло некоторое время, но могу сделать предложение. Линии не реагируют на мышь/указатель на события в pixijs.
Вместо этого вы можете захотеть сопровождать преобразованный прямоугольник альфа-значением 0 и слушать мышь/указатель с этим прямоугольником.
Например, давайте изменим альфа-значение линии, когда мышь/указатель наводит соответствующий прямоугольник.
const app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x283230
});
document.body.appendChild(app.view);
// 1. PRELIMINARY COMPUTATIONS
// Coordinates of the end points of a line
let x0 = 100;
let y0 = 100;
let x1 = 200;
let y1 = 200;
// Find midpoint for translation
let xmid = 0.5*(x0+x1);
let ymid = 0.5*(y0+y1);
// Length of the line
let length = Math.hypot(x0-x1, y0-y1);
// Alignment angle of the line, i.e. angle with the x axis
let angle = Math.atan((y1-y0)/(x1-x0));
// 2. LINE
line = new PIXI.Graphics();
// Arbitrary line style, say we have a non-white background
line.lineStyle(8,0xffffff,1);
line.moveTo(x0,y0);
line.lineTo(x1,y1);
// 3. ACCOMPANYING RECTANGLE
line.rectangle = new PIXI.Graphics();
line.rectangle.beginFill(0xffffff);
// Since we are going to translate, think of 0,0 is the center point on the rectangle
// Width of the rectangle is selected arbitrarily as 30
const width = 30;
line.rectangle.drawRect(-length/2,-width/2,length,width);
line.rectangle.endFill();
line.rectangle.alpha = 0;
line.rectangle.interactive = true;
line.rectangle.on("pointerover", reactOver);
line.rectangle.on("pointerout", reactOut);
// Apply transformation
line.rectangle.setTransform(xmid, ymid,1,1,angle);
app.stage.addChild(line);
// Add rectangle to the stage too.
app.stage.addChild(line.rectangle);
// Let's change alpha value of the line when user hovers.
function reactOver(){
line.alpha = 0.5;
}
function reactOut(){
line.alpha = 1;
}
К PEN, наведите курсор на строку в pixijs
Мы можем расширить эту логику, например, до прямоугольника. Но на этот раз вам нужны два сопутствующих прямоугольника (с альфа=0), один из которых шире, а другой уже, чем незаполненный прямоугольник. Например,
const app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x283230
});
document.body.appendChild(app.view);
const x = 100;
const y = 100;
const width = 150;
const height = 100;
const hoverWidth = 20;
const rect = new PIXI.Graphics();
rect.lineStyle(4, 0xffffff,1);
rect.drawRect(x,y,width,height);
rect.outer = new PIXI.Graphics();
rect.inner = new PIXI.Graphics();
// Fill outer
rect.outer.alpha = 0;
rect.outer.beginFill(0xffffff);
rect.outer.drawRect(x-hoverWidth/2, y-hoverWidth/2, width+hoverWidth, height+hoverWidth);
rect.outer.endFill();
// Fill inner
rect.inner.alpha = 0;
rect.inner.beginFill(0xffffff);
rect.inner.drawRect(x+hoverWidth/2, y+hoverWidth/2, width-hoverWidth, height-hoverWidth);
rect.inner.endFill();
// Add interaction and listeners
rect.outer.interactive = true;
rect.inner.interactive = true;
rect.outer.on("pointerover", pOverOuter);
rect.outer.on("pointerout", pOutOuter);
rect.inner.interaction = true;
rect.inner.on("pointerover", pOverInner);
rect.inner.on("pointerout", pOutInner);
app.stage.addChild(rect);
app.stage.addChild(rect.outer);
app.stage.addChild(rect.inner);
// Listeners
let overOuter = false;
let overInner = false;
function pOverOuter(){
overOuter = true;
changeAlpha();
// rect.alpha = 0.5;
}
function pOutOuter(){
overOuter = false;
changeAlpha();
}
function pOverInner(){
overInner = true;
changeAlpha();
// rect.alpha = 1;
}
function pOutInner(){
overInner = false;
changeAlpha();
// rect.alpha = 0.5;
}
function changeAlpha(){
rect.alpha = (overOuter && !overInner)? 0.5: 1;
}
Для первого требования попробуйте создать отдельные графические объекты для рисования каждой линии и установить альфа для каждой линии. Для вашего второго требования, вам нужно установить интерактивное свойство объекта graphics (linksGraphics) в true, как показано ниже,
linksGraphics.interactive = true;
и затем присоедините функцию, которая будет выполняться при наведении мыши, как показано ниже,
var mouseOverAction = function () {
//Some code
};
linksGraphics.on('mouseover', mouseOverAction);