Skip to content

Commit

Permalink
feat(color): Intent to ship color.onover
Browse files Browse the repository at this point in the history
- Implmentation of color.onover new option.
- It also fixes data.onover/out for arc type on touch environment

Fix #754
Ref #768
Close #772
  • Loading branch information
netil committed Feb 15, 2019
1 parent 9ad9817 commit 5ec2d9e
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 73 deletions.
22 changes: 22 additions & 0 deletions demo/demo.js
Expand Up @@ -2425,6 +2425,28 @@ d3.select(".chart_area")
}
}
},
ColorOnover: {
options: {
data: {
columns: [
["data1", 230, 200, 100, 400, 150, 250],
["data2", 150, 320, 210, 240, 115, 125],
["data3", 130, 220, 140, 200, 250, 450]
],
groups: [
["data1", "data2", "data3"]
],
type: "bar"
},
color: {
onover: {
data1: "#868484",
data2: "black",
data3: "rgb(202, 202, 202)"
}
}
}
},
ColorPattern: {
options: {
data: {
Expand Down
8 changes: 5 additions & 3 deletions spec/interactions/interaction-spec.js
Expand Up @@ -615,16 +615,18 @@ describe("INTERACTION", () => {

util.fireEvent(eventRect, "mouseover");
util.fireEvent(eventRect, "mouseout");

expect(spy1.calledTwice).to.be.true;
expect(spy2.calledTwice).to.be.true;
});

it("set options interaction.inputType.touch=true", () => {
args.interaction.inputType.touch = true;

spy1.resetHistory();
spy2.resetHistory();
});

it("should be called callbacks for touch events", done => {
chart.internal.callOverOutForTouch.last = null;

util.simulator(chart.$.svg.node(), {
pos: [250,150],
deltaX: -100,
Expand Down
121 changes: 120 additions & 1 deletion spec/internals/color-spec.js
Expand Up @@ -6,7 +6,7 @@
/* global describe, beforeEach, it, expect */
import util from "../assets/util";
import CLASS from "../../src/config/classes";
import {isString} from "../../src/internals/util";
import {isFunction, isObject, isString} from "../../src/internals/util";

describe("COLOR", () => {
let chart;
Expand Down Expand Up @@ -225,4 +225,123 @@ describe("COLOR", () => {
it("check for stroke", checkStroke);
});
});

describe("color.onover", () => {
before(() => {
args = {
data: {
columns: [
["data1", 10, 20, 30],
["data2", 20, 10, 25]
],
types: {
data2: "bar"
},
},
color: {
onover: "yellow"
}
}
});

// check color.onover
const checkColor = (chart, colorOnover) => {
const main = chart.$.main;
const eventRect = main.select(`.${CLASS.eventRect}-1`).node();
const shape = main.selectAll(`.${CLASS.shape}-1`);
const originalColor = [];

shape.each(function() {
originalColor.push({
stroke: this.style.stroke,
fill: this.style.fill
});
});

util.fireEvent(eventRect, "mouseover");

shape.each(function(d) {
let color = colorOnover;

if (isObject(color)) {
color = color[d.id];
} else if (isFunction(color)) {
color = color();
}

expect(this.style.stroke).to.be.equal(color);
expect(this.style.fill).to.be.equal(color);
});

// check for restoration
util.fireEvent(eventRect, "mouseout");

shape.each(function(d, i) {
expect(this.style.stroke).to.be.equal(originalColor[i].stroke);
expect(this.style.fill).to.be.equal(originalColor[i].fill);
});
};

it("check the onover color when string value is given", () => {
checkColor(chart, args.color.onover);
});

it("set options color.onover={ ... }", () => {
args.data.types.data1 = "bar";
args.data.gropus = [["data1", "data2"]];

args.color.onover = {
data1: "red",
data2: "yellow"
};
});

it("check the onover color when object value is given", () => {
checkColor(chart, args.color.onover);
});

it("set options color.onover=function(){}", () => {
args.color.onover = function() {
return "green";
};
});

it("check the onover color when function value is given", () => {
checkColor(chart, args.color.onover);
});

it("set options data.type=pie", () => {
args = {
data: {
columns: [
["data1", 10],
["data2", 20]
],
type: "pie"
},
color: {
onover: "red"
},
transition: {
duration: 0
}
};
});

it("check for the arc type", done => {
setTimeout(() => {
const main = chart.$.main;
const arc = main.select(`.${CLASS.arc}-data1`).node();
const originalColor = arc.style.fill;

util.fireEvent(arc, "mouseover");
expect(arc.style.fill).to.be.equal(args.color.onover);

util.fireEvent(arc, "mouseout");
expect(arc.style.fill).to.be.equal(originalColor);

done();
}, 500);
});
});
});
16 changes: 16 additions & 0 deletions src/config/Options.js
Expand Up @@ -1163,6 +1163,7 @@ export default class Options {
* @name color
* @memberof Options
* @type {Object}
* @property {String|Object|Function} [color.onover] Set the color value for each data point when mouse/touch onover event occurs.
* @property {Array} [color.pattern] custom color pattern
* @property {Function} [color.tiles] if defined, allows use svg's patterns to fill data area. It should return an array of [SVGPatternElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGPatternElement).
* - **NOTE:** The pattern element's id will be defined as `bb-colorize-pattern-$COLOR-VALUE`.<br>
Expand Down Expand Up @@ -1207,12 +1208,27 @@ export default class Options {
* unit: "value",
* values: [10, 20, 30, 40, 50], // when the value is 20, 'green' will be set and the value is 40, 'orange' will be set.
* max: 30 // the equation for max is: value*100/30
* },
*
* // set all data to 'red'
* onover: "red",
*
* // set different color for data
* onover: {
* data1: "red",
* data2: "yellow"
* },
*
* // will pass data object to the callback
* onover: function(d) {
* return d.id === "data1" ? "red" : "green";
* }
* }
*/
color_pattern: [],
color_tiles: undefined,
color_threshold: {},
color_onover: undefined,

/**
* Legend options
Expand Down
60 changes: 40 additions & 20 deletions src/interactions/interaction.js
Expand Up @@ -10,7 +10,7 @@ import {
import {drag as d3Drag} from "d3-drag";
import ChartInternal from "../internals/ChartInternal";
import CLASS from "../config/classes";
import {emulateEvent, extend, isBoolean, isNumber} from "../internals/util";
import {emulateEvent, extend, isBoolean, isNumber, isObject} from "../internals/util";

extend(ChartInternal.prototype, {
/**
Expand Down Expand Up @@ -84,7 +84,6 @@ extend(ChartInternal.prototype, {
bindTouchOnEventRect(isMultipleX) {
const $$ = this;
const config = $$.config;
let lastRectIndex;

const getEventRect = () => {
const touch = d3Event.changedTouches[0];
Expand All @@ -103,24 +102,14 @@ extend(ChartInternal.prototype, {
return index;
};

// call onover/onout callback for touch event
const callOverOut = index => {
if (index !== lastRectIndex) {
isNumber(lastRectIndex) && $$.setOverOut(lastRectIndex, false);
isNumber(index) && $$.setOverOut(index, true);

lastRectIndex = index;
}
};

const selectRect = context => {
if (isMultipleX) {
$$.selectRectForMultipleXs(context);
} else {
const eventRect = getEventRect();
const index = getIndex(eventRect);

callOverOut(index);
$$.callOverOutForTouch(index);

index === -1 ?
$$.unselectRect() :
Expand Down Expand Up @@ -172,7 +161,7 @@ extend(ChartInternal.prototype, {
selectRect(this);
} else {
$$.unselectRect();
callOverOut();
$$.callOverOutForTouch();
}
})
.on("touchend.eventRect", () => {
Expand Down Expand Up @@ -403,16 +392,47 @@ extend(ChartInternal.prototype, {
$$.unexpandBars();
},

setOverOut(index, isOver) {
/**
* Handle data.onover/out callback options
* @param {Boolean} isOver
* @param {Number|Object} d
* @private
*/
setOverOut(isOver, d) {
const $$ = this;
const config = $$.config;
const isArc = isObject(d);

// Call event handler
if (index !== -1) {
isOver && $$.expandCirclesBars(index, null, true);
if (isArc || d !== -1) {
const callback = config[isOver ? "data_onover" : "data_onout"].bind($$.api);

!$$.isMultipleX() && $$.main.selectAll(`.${CLASS.shape}-${index}`).each(callback);
config.color_onover && $$.setOverColor(isOver, d, isArc);

if (isArc) {
callback(d);
} else {
isOver && $$.expandCirclesBars(d, null, true);
!$$.isMultipleX() && $$.main.selectAll(`.${CLASS.shape}-${d}`).each(callback);
}
}
},

/**
* Call data.onover/out callback for touch event
* @param {Number|Object} d target index or data object for Arc type
* @private
*/
callOverOutForTouch(d) {
const $$ = this;
const callee = $$.callOverOutForTouch;
const last = callee.last;

if (isObject(d) && last ? d.id !== last.id : (d !== last)) {
(last || isNumber(last)) && $$.setOverOut(false, last);
(d || isNumber(d)) && $$.setOverOut(true, d);

callee.last = d;
}
},

Expand Down Expand Up @@ -459,7 +479,7 @@ extend(ChartInternal.prototype, {
return;
}

$$.setOverOut(d.index, true);
$$.setOverOut(true, d.index);
})
.on("mousemove", function(d) {
// do nothing while dragging/flowing
Expand Down Expand Up @@ -487,7 +507,7 @@ extend(ChartInternal.prototype, {
}

$$.unselectRect();
$$.setOverOut(d.index, false);
$$.setOverOut(false, d.index);
});
}

Expand Down
40 changes: 39 additions & 1 deletion src/internals/color.js
Expand Up @@ -6,7 +6,7 @@ import {select as d3Select} from "d3-selection";
import {scaleOrdinal as d3ScaleOrdinal} from "d3-scale";
import ChartInternal from "./ChartInternal";
import CLASS from "../config/classes";
import {notEmpty, extend, isFunction} from "./util";
import {notEmpty, extend, isFunction, isObject, isString} from "./util";

/**
* Set pattern's background color
Expand Down Expand Up @@ -157,5 +157,43 @@ extend(ChartInternal.prototype, {

return color;
} : null;
},

/**
* Set the data over color.
* When is out, will restore in its previous color value
* @param {Boolean} isOver true: set overed color, false: restore
* @param {Number|Object} d target index or data object for Arc type
* @private
*/
setOverColor(isOver, d) {
const $$ = this;
const config = $$.config;
const onover = config.color_onover;
let color = isOver ? onover : $$.color;

if (isObject(color)) {
color = d => {
const id = d.id;

return id in onover ? onover[id] : $$.color(id);
};
} else if (isString(color)) {
color = () => onover;
}

// when is Arc type
if (isObject(d)) {
$$.main.selectAll(`.${CLASS.arc}-${d.id}`)
.style("fill", color(d));
} else {
$$.main.selectAll(`.${CLASS.shape}-${d}`)
.each(function(d) {
const val = color(d);

this.style.stroke = val;
this.style.fill = val;
});
}
}
});

0 comments on commit 5ec2d9e

Please sign in to comment.